react-redux
react-redux copied to clipboard
Dispatching at the same time as setState causes two renderings
What version of React, ReactDOM/React Native, Redux, and React Redux are you using?
- React: 18.0.0
- ReactDOM:18.0.0
- Redux Toolkit:1.8.1
- React Redux:8.0.1
What is the current behavior?
Synchronous calls to dispatch and setState within useEffect will cause separate re-rendering.
Since it may not be possible to check visually, try using the Profiler in the React Developer Tools to see how it works.
https://codesandbox.io/s/brave-dew-cc7p4p?file=/src/features/counter/CounterEditor.tsx
What is the expected behavior?
The re-rendering occurs only once.
Which browser and OS are affected by this issue?
Chrome/100.0.4896.127, Windows10
Did this work in previous versions of React Redux?
- [X] Yes
Since the video was difficult to understand, I upload the original video file. screen-recording.zip
Without having fully investigated yet: batching and render timing are owned by React, not React-Redux. We don't have full control over that.
I would have expected that all updates queued in a useEffect
would be batched together, especially under React 18. But, the nuances of this one are tricky.
Either way I don't think there's anything we can specifically do here, and I don't think this is actually a "bug".
The OP has used React.StrictMode
, so I have suspected that makes useEffect
run twice.
But, unfortunately, I could made another repro for this issue, without StrictMode.
This should run ok with react-redux@7 + react@18, but if you run this with react-redux@8 + react@18, it throws an error, Maximum update depth exceeded
.
Actually, the example I have made can be fixed, if you use dependencies for the useEffect.
But this example shows that if you call setState
and dispatch
, a rerender, with updates from dispatch and without updates from setState, can happen even if you call setState
prior to the dispatch
.
Yes, it's actually that. Good call!
Isn't that still a problem that we should maybe bring up with the React team?
I mean, that problem essentially occurs because state updates happen out of order - the later Redux update happens before the earlier state setter call.
That essentially means that Redux updates break out of the automated batching here, which was not a problem before when react-redux
used setState
to trigger a rerender.
Andarist pointed out this is likely the same thing as https://github.com/facebook/react/issues/24831
It seems like problem is more complex than just rendering twice.
Dispatching redux action in the same effect where a local state is updated cancels the local state update.
I've created a codesandbox with a simple to reproduce example.
https://codesandbox.io/s/friendly-worker-fdyvqk
Probably it's on React side as mentioned but posting here maybe it will be helpful.
This will be changed on the React side - unfortunately at this point there's not really anything we can do about it: https://github.com/facebook/react/issues/25191#issuecomment-1244805920