question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Thinking 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:closed
  • Created 3 years ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
Ephemcommented, Apr 20, 2020

Yup! That’s why I didn’t open a new issue, I just added it for context as a hands on problem. 😄

1reaction
Ephemcommented, Apr 20, 2020

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:

  • Is canceling a side effect not in itself a side effect? Is it safe to run that within the reducer? Do we need to somehow trigger the cancelling of the effect in the actual effect cleanup behind the scenes to be Concurrent Mode safe?
  • Is it up to the consumer of this library to dispatch 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.

  • Is it up to the consumer to call CANCEL on an old fetch before doing a new one? If not, how do you handle that in this paradigm? With useEffect 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?

Read more comments on GitHub >

github_iconTop 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 >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found