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",
...
}
}
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
destroyusesthis.For regular functions, the value of
thisis determined by how the function is called. So if you have code that saysview.destroy(), then the charactersview.are the reason thatthisgets set toview. That's why() => view.destroy()one works: you are explicitly saying whatthisshould 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 aboutview, it just knows you returned a function. So when react later calls your function, it doesn't know what to setthisto, and sothisgets set to undefined. Since it's undefined,this.pluginscauses the error you see.