You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
const[boolValue,setBoolValue]=useState(false);const_count=useSelector((state)=>{// NOTE: we return new array herereturn[];});useEffect(()=>{// NOTE: we always set to `true` heresetBoolValue(true);},[_count]);// effect depends on an unstable-idenity value `_count`
The above code sandbox has a few notable points:
React version v18
the selector callback function used in useSelector(callback) does NOT have a stable-identity (Object.is equals)
the selector callback returns an selectedValue object which does NOT have stable-identity
there is an useEffect() relying on the above selectedValue in its dependencies list
the component's state should not change after 2nd render because setBoolValue(true); always
In the code sandbox, we observe that the component keeps re-rendering itself.
Without specific short-circuit code:
// Stop infinite loop after certain render countif(window.renderCount>=STOP_RENDER)return;
the component will re-render infinitely.
What is the expected behavior?
I am not sure if this is a bug / new expected behaviour in react-reduxv8
Granted the existing old code was not ideal:
the selector callback function used in useSelector(callback) does NOT have stable-identity (Object.is equals)
the selector callback returns an selectedValue object which does NOT have stable-identity
However, when reading the code, we do not expect the component to re-render infinitely:
eventually, the component will settle because:
there are no new update from the state store
the component's state will stop changing because of setBoolValue(true); always
useSelector, useEffect, and setState() have known defined behaviors based on object references. useSelector re-renders the component if you return a new reference. useEffect executes if a value in the deps array is a new reference. setState() forces a re-render if you pass in a new reference as the value.
Note that we do explicitly describe useSelector's behavior in the docs and tell you not to write selectors that always return a new reference unconditionally:
In other words, a selector should only return a new reference if the input data has truly changed.
Now, given the example code you showed, I would not expect that component to keep re-rendering. React should see that you're passing in a value that is the same as the existing state value, and bail out:
So I don't immediately know why this component keeps re-rendering multiple times.
But in general: both React and React-Redux expect that you only create new references when values actually change, and rendering behavior does rely on you following those rules correctly.
What version of React, ReactDOM/React Native, Redux, and React Redux are you using?
v18.2.0
v18.2.0
@reduxjs/toolkit
v1.9.3
v8.0.5
What is the current behavior?
I encountered an infinite React re-rendering loop bug when upgrading an existing code repo from
react-redux
v7
->v8
Reproduction sandbox: https://codesandbox.io/s/redux-v8-issue-vr25b1?file=/src/features/counter/Counter.js
Code sample:
The above code sandbox has a few notable points:
callback
function used inuseSelector(callback)
does NOT have a stable-identity (Object.is
equals)callback
returns anselectedValue
object which does NOT have stable-identityuseEffect()
relying on the aboveselectedValue
in its dependencies listsetBoolValue(true);
alwaysIn the code sandbox, we observe that the component keeps re-rendering itself.
Without specific short-circuit code:
the component will re-render infinitely.
What is the expected behavior?
I am not sure if this is a bug / new expected behaviour in
react-redux
v8
Granted the existing old code was not ideal:
callback
function used inuseSelector(callback)
does NOT have stable-identity (Object.is
equals)callback
returns anselectedValue
object which does NOT have stable-identityHowever, when reading the code, we do not expect the component to re-render infinitely:
setBoolValue(true);
alwaysreact-redux
v7
I am not too familiar with internal of
react-redux
, could this behaviour is a by product of this useSyncExternalStore behaviour ?I tested a few things using the above codesandbox, and these help preventing the infinite loop:
v17
react-redux
tov7
callback
function has stable-identityselectedValue
object has stable-identityWhich browser and OS are affected by this issue?
Chrome Version 114.0.5735.45 (Official Build) beta (x86_64)
Did this work in previous versions of React Redux?
The text was updated successfully, but these errors were encountered: