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.

inconsistent behaviour with strict mode and useEffect

See original GitHub issue

I have a component which is subscribed to value from my store, which it uses in it’s render output. I attempted to add a useEffect which would trigger when value changed, and perform some side effect, e.g:

function Effect() {
  const value = useStore(state => state.value);

  useEffect(() => {
    someSideEffect(value)
  }, [value]);

  return value;
}

I noticed that the useEffect wasn’t firing when the value changed, despite the rendered output updating.

Eventually i reduced this down to React.StrictMode, if i remove this, everything works how I expect it to, but when it’s on, value changing just caused the component to render 4 times with no useEffect calls.

Minimal example: https://codesandbox.io/s/hungry-hoover-khx8k

But! It gets even weirder than that… 😫

If you look in the codesandbox, you can see that when using StrictMode, calling test() in the console will not cause the effect to fire, but pressing the button, which fires the same update function, only grabbed via useStore, works fine.

There is also a version of the Effect component in the sandbox which uses the more direct api.subscribe style of useEffect, and this one works with both the button and the test() function call, even with strict mode turned on.

I can’t get my head around it. Am I doing something wrong?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:4
  • Comments:12 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
beeglebugcommented, Jun 16, 2020

Ahhh ok, yeah I think I get it now. It’s not so much that the code itself is outside the react tree, but the event that triggers the state change was a react synthetic event (the click handler on the button in this case).

I’m not sure this gets me any closer to a workable solution, but it sure is expanding my knowledge of react inner workings, so thanks again for your help.

On Tue, 16 Jun 2020, 22:19 Renaud Déchaux, notifications@github.com wrote:

If you look at the zustand source code you can see that it uses a little trick with an incrementing useReducer value which forces components using the store to see the changes, even when done from outside the React tree. This is an advertised feature of zustand in the readme, and an important part of why it’s such a great library!

The important point is not the use of useReducer outside of the React tree by zustand, it is the event that triggered it. In the React doc https://reactjs.org/docs/concurrent-mode-adoption.html#feature-comparison :

Legacy mode has automatic batching in React-managed events but it’s limited to one browser task. Non-React events must opt-in using unstable_batchedUpdates. In Blocking Mode and Concurrent Mode, all setStates are batched by default.

The render phase works, but there is something going on with the commit phase, and it’s where my core React knowledge are too limited to know if it’s actually an issue or a normal behavior.

Note that once you use unstable_batchedUpdates in your example, the useEffect is working:

https://codesandbox.io/s/zustand-use-effect-8gpis

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/react-spring/zustand/issues/115#issuecomment-645017575, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHJAMDFBVCPSURBFCMRLALRW7OVXANCNFSM4N6JSB3A .

1reaction
beeglebugcommented, Jun 16, 2020

Right, that should have it back to the original minimal reproduction of the original issue, sorry about that.

I’d be very keen to get your opinion again, it’s entirely possible that i’m just making a simple mistake somewhere, and to be honest at this point I hope that I am. Am I wrong in expecting the useEffect to fire when calling test() in the console?

Read more comments on GitHub >

github_iconTop Results From Across the Web

inconsistent behaviour with strict mode and useEffect #115
I noticed that the useEffect wasn't firing when the value changed, despite the rendered output updating. Eventually i reduced this down to React ......
Read more >
The tricky behavior of useEffect hook in React 18 - Medium
React 18 introduces a new development-only check to Strict Mode. This new check will automatically unmount and remount every component, whenever a component ......
Read more >
React Hooks showing inconsistent behaviour - Stack Overflow
React only rerenders if the reference to the object on state has changed (or if it's scalar, the value itself). You must create...
Read more >
Hooks API Reference - React
Doing so will lead to confusing bugs and inconsistencies in the UI. Instead, use useEffect . The function passed to useEffect will run...
Read more >
My React components render twice and drive me crazy
Others have noticed this behaviour, but they believe this is how React ... StrictMode is a wrapper to help prepare apps for async...
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