Effect cleanup
See original GitHub issueThinking out loud: we need some way to control the cleanup of effects. Right now, useEffectReducer
treats effects as fire-and-forget, which is fine for many use-cases, but can introduce memory leaks or undesired behaviors for certain effects that are supposed to have a specific lifetime.
One solution: exec(effect)
can return an entity which can be explicitly managed in the reducer state:
const someReducer = (state, event, exec) => {
if (event.type === 'FETCH') {
return {
// ...
effect: exec({ type: 'fetch', user: 'David' })
}
else if (event.type === 'CANCEL') {
// stop effect
state.effect.stop();
return {/* ... */}
}
}
The effect
returned from exec(...)
will be an opaque object that (for now) just has a unique id
and a .stop()
method. This will call the disposal function returned from the effect:
const [state, dispatch] = useEffectReducer(someReducer, initialState, {
fetch: () => {
// ...
return () => {
// cancel fetch request
}
}
});
Issue Analytics
- State:
- Created 3 years ago
- Comments:8 (3 by maintainers)
Top Results From Across the Web
Using the Effect Hook - React
When exactly does React clean up an effect? React performs the cleanup when the component unmounts. However, as we learned earlier, effects run...
Read more >Understanding React's useEffect cleanup function
React's useEffect cleanup function saves applications from unwanted behaviors like memory leaks by cleaning up effects.
Read more >React useEffect cleanup - Daily Dev Tips
How to use the cleanup effect in a react useEffect hook. ... React's useEffect hook is a super hook to run side effects....
Read more >Demystifying useEffect's clean-up function - Max Rozen
I am the effect. Even though the clean-up function is running in the new render, it still has the old prop values since...
Read more >React useEffect cleanup: How and when to use it
To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function. The message is straightforward.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Yup! That’s why I didn’t open a new issue, I just added it for context as a hands on problem. 😄
Thanks for this library and opening this issue to discuss! I’m by no means an expert and I’ll also just be thinking out loud here.
I think introducing effect cleanup is hard, not specifically because the cleanup itself is hard to implement correctly (which I also think it is), but also because thinking about these things exposes a few mismatches with the effect model, where I think it is very easy to create footguns for users when it comes to async effects.
The example you posted is a start, but some questions immediately spring to mind:
CANCEL
when a component unmounts? Would it be possible to do automatic effect cleanup in that case?What is trickier though is how to handle race conditions.
CANCEL
on an old fetch before doing a new one? If not, how do you handle that in this paradigm? WithuseEffect
you often keep track of if the effect is stale or not, what is the equivalent here? Can we make something better?I don’t have any answers. I know @dai-shi implemented something like this using
AbortSignal
in user-reducer-async abort examples but I have no idea if it works as intended in all cases. Also, while nicer than juggling effects manually, any solution where you have to check for staleness yourself in userland is a bit cumbersome. I have no idea how to get around that though.I’m not sure how to even approach this problem in a structured way to be honest. Maybe by collecting pseudo test-cases or requirements?