I have a question about useEffect
's cleanup callback function. In one word, return cleanup
gives an error, but return () => cleanup()
works well. Yes, they are different, but how are they different? Does anyone know how to explain? Thanks,
I came across this question while I am writing with codemirror.
The error message I see is
Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'plugins')
My hooks
export const useCodeMirror = () => {
const state = ...
const parent = ...
useEffect(() => {
const view = new EditorView({state: state, parent: parent})
// return view.destroy raises an error
return () => view.destroy() // works perfectly
}, [element])
}
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;
}
package.json
{
"dependencies": {
...
"codemirror": "^6.0.1",
...
}
}
CodePudding user response:
It's normally fine to return a cleanup function directly, rather than wrapping it in an additional arrow function. The only reason the additional function is needed in this case because destroy
uses this
.
For regular functions, the value of this
is determined by how the function is called. So if you have code that says view.destroy()
, then the characters view.
are the reason that this
gets set to view
. That's why () => view.destroy()
one works: you are explicitly saying what this
should be, as you call the function.
But if you just return view.destroy
, you are not calling the function, just returning a reference of it to react. React doesn't know anything about view
, it just knows you returned a function. So when react later calls your function, it doesn't know what to set this
to, and so this
gets set to undefined. Since it's undefined, this.plugins
causes the error you see.
CodePudding user response:
Because you're direct returning view.destroy() from useEffect return statement. But it should be called from a callback function.
useEffect(() => {
....
// return view.destroy raises Unhandled Runtime Error
***this should be returned from a callback function.
like this***
**return () => view.destroy()**
....
}