DEV Community

Aurora
Aurora

Posted on

The problem with callbacks depending on state inside useEffect you might not be aware of!

While writing React code. I have come across an issue that was really hard to figure out why it happened, but had a really fix, and so I thought I'd publish it for future devs to be aware of!

The setup

So you might have a react functional component that uses the useState hook, some useEffects and that has some complicated logic inside a listener, and so you've placed the logic inside a callback that references the state:

const MyComponent = () => {
    const [myState, setMyState] = useState()

    const myHelper = () => {
        /* does stuff based on myState in here*/
    }

    useEffect(() => {
        addListener(myHelper())
    }, [/* some dependencies */])

    return (<div/>)
}
Enter fullscreen mode Exit fullscreen mode

What you might notice is, when the state changes, the handler being executed by the listener still uses the old state!

It seems like the it captures its environment and uses that!

This can be really confusing to figure out why it does this.

The solution

To solve this, you need to do two things:

  • add the state to the dependency array
  • remove the listener on state change
useEffect(() => {
    // store the listener to be able to remove it later
    const listener = addListener(myHelper);
    return () => {
        // actually remove the listener in the cleanup
        listener.remove();
    };
    // add myState to the dependencies              
}, [myState, /* other dependencies*/])
Enter fullscreen mode Exit fullscreen mode

And that's it!

Conclusion

This might seem obvious at first, add all the states that the useEffect depends on inside the dependencies array.

But the tricky part here is, you might have more dependencies than you think at first!

It's not just the states directly used inside the useEffect hook, but it's also all the states used by functions that are called in here!

So the next time you think of what dependencies need to go in the dependency array, don't just look at what states are used inside the hook, but also at which ones are used in functions inside the hook!

Top comments (0)