You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React useEffect中return cleanup与return ()=>cleanup()的差异及报错解析

React useEffect清理CodeMirror实例的回调差异问题解析

问题场景

在基于CodeMirror ^6.0.1开发React自定义Hook时,遇到useEffect清理回调的异常:

  • 直接返回view.destroy会触发错误:Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading 'plugins')
  • 返回() => view.destroy()则能正常完成实例销毁

自定义Hook代码:

export const useCodeMirror = () => {
  const state = ...
  const parent = ...
  
  useEffect(() => {
    const view = new EditorView({state: state, parent: parent})
    // 报错写法
    // return view.destroy
    // 正常写法
    return () => view.destroy()
  }, [element])
}

报错原因分析

核心差异在于函数调用时的this指向:

  1. 当直接返回view.destroy时,React执行清理回调时是将这个函数作为独立函数调用的。在React默认启用的严格模式下,独立调用的函数this指向undefined。而CodeMirror的destroy方法内部依赖this指向EditorView实例来访问plugins、inputState等属性,因此会抛出属性读取失败的错误。
  2. 当返回() => view.destroy()时,view.destroy()是通过对象方法调用的形式执行,此时this会自动绑定到view实例上,destroy方法能正常访问实例的所有属性,因此可以顺利执行销毁逻辑。

CodeMirror destroy方法源码佐证

CodeMirror的destroy方法源码(来自node_modules/@codemirror/view/dist/index.js L:6740-6750):

destroy() {
    for (let plugin of this.plugins)
        plugin.destroy(this);
    this.plugins = [];
    this.inputState.destroy();
    this.dom.remove();
    this.observer.destroy();
    if (this.measureScheduled > -1)
        cancelAnimationFrame(this.measureScheduled);
    this.destroyed = true;
}

方法内多处使用this访问实例属性,一旦this指向错误,必然导致属性读取失败。

结论

在React useEffect的清理回调中,若要调用类实例的方法,不能直接返回方法引用,必须通过函数包裹的形式调用,确保方法执行时this指向正确的实例对象。

内容的提问来源于stack exchange,提问作者Wt.N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 20:45:50