I am trying to optimize my react code by fixing any memory leaks. I am using createAsyncThunk canceling-while-running to cancel requests, if my component unmounts.
I have three reducers inside two useEffect
hooks. One dispatches when the component mounts and the other two dispatches when the response from the first dispatched reducer arrives.
Below is my code:
useEffect(() => {
const promise = dispatch(bookDetails(bookId))
return () => promise.abort()
}, [])
// this is triggered when the response from the dispatched "bookDetails" reducer arrives
// and get stored in the "book" variable as shown in dependency array
useEffect(() => {
let promise1, promise2
if (book._id !== undefined) {
promise1 = dispatch(getComments(book._id))
promise2 = dispatch(relatedBooks({ genre: book.genre }))
}
return () => {
promise1.abort() // BookDetails.jsx:58:1
promise2.abort()
}
}, [book])
When the component mounts the second useEffect
gives me an error, given below:
BookDetails.jsx:58 Uncaught TypeError: Cannot read properties of undefined (reading 'abort')
at BookDetails.jsx:58:1
at safelyCallDestroy (react-dom.development.js:22932:1)
at commitHookEffectListUnmount (react-dom.development.js:23100:1)
at invokePassiveEffectUnmountInDEV (react-dom.development.js:25207:1)
at invokeEffectsInDev (react-dom.development.js:27351:1)
at commitDoubleInvokeEffectsInDEV (react-dom.development.js:27324:1)
at flushPassiveEffectsImpl (react-dom.development.js:27056:1)
at flushPassiveEffects (react-dom.development.js:26984:1)
at performSyncWorkOnRoot (react-dom.development.js:26076:1)
at flushSyncCallbacks (react-dom.development.js:12042:1)
I tried few things but it didn't workout for me.
CodePudding user response:
Since the promise1
and promise2
is assigned within the condition book._id !== undefined
, it has the possibility of not being assigned. Simple quick fix is checking a condition when invoking .abort()
. Something like promise?.abort()
or typeof promise?.abort === 'function' && promise.abort()
.
CodePudding user response:
There is a condition on dispatching the asynchronous actions in the second useEffect
hook. This means that promise1
and promise2
are potentially undefined. Only return the cleanup function if the actions are dispatched.
Example:
useEffect(() => {
if (book._id && book.genre) {
const promise1 = dispatch(getComments(book._id));
const promise2 = dispatch(relatedBooks({ genre: book.genre }));
return () => {
promise1.abort();
promise2.abort();
};
}
}, [book]);