-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
useSelector() in combination with lazy loaded components breaks with react v18 #1977
Comments
Hmm. I honestly don't think I understand what this sandbox is trying to show, or what the repro steps are ("full reload"?). Also, why are there multiple separate FWIW in v8 we're ultimately just using React's |
Thanks for looking at this bug report. Let me try to give you some more information on it. BackgroundThe code is actually from a pretty big application which I tried to break down as much as possible. Therefore, there might be some odd looking constructs.
ReproductionI have modified the reproduction to make it clearer. The issue basically is that on clicking the button, the upper value is not updated although the store is updated with the new value which can be seen in the console.log output. An example of a broken run: SubscriptionsI have seen that you are using react-redux/src/components/Provider.tsx Line 34 in 8d03182
The problematic code is in the cleanup function of the useEffect where the subscription is unsubscribed. react-redux/src/components/Provider.tsx Line 53 in 8d03182
This removes all previous subscriptions (including useSelector subscriptions) from being fired on store changes. react-redux/src/utils/Subscription.ts Line 135 in 8d03182
This happens when the React VersionThis actually works correctly when using |
Hmm. I sorta see the "outer doesn't update" behavior in the sandbox... but if I clone this project and build+run it locally, both numbers update fine, in both a dev and production build. I'm still confused over what you're describing overall. Yes, components stop subscribing when they unmount, because they're unmounting. And if a |
@markerikson I have changed the codesandbox by delaying the lazy loading of the component by 1s. After doing that I can reproduce it every time locally. I was also really confused about the behavior; however the inner components seems not to be unmounted and are still relying on the outdated subscriptions which are no longer firing. There seems to be some behavior change between react v17 & v18 because using the ReactDOM.render api makes the issue disappear completely. |
I am not able to give some reproducible stuff, however if this may help: we have a project with react-redux and react-routeur. Routes are declared lazily ( After the migration to React 18 AND using the new Now if I move the top menu into the final components (that are displayed within the routing), or if I remove the lazy loading, then it works great. |
Seems to me that the problem is that the Provider is inside the Suspense, moving it outside fixes the problem <Provider store={store}>
<Suspense>
<Counter />
</Suspense>
</Provider>` |
Yes, however it worked with React 17 or without |
@francescocaveglia solution did not work for us as we do not use a single redux store for our whole application but multiple stores for all our more comprehensive, more state driven tools. This leads to quite a few suspense boundaries outside these tools causing the problems described in this ticket. So AFAICT this problem is because So … to solve this problem for us we use the mechanic behind const [store] = useState(() => configureStore({ /* ... */ }));
const [renderKey, setRenderKey] = useState(1);
useLayoutEffect(() => {
setRenderKey((key) => key + 1);
}, []);
return (
<Provider store={store} key={renderKey}>
<Suspense>{children}</Suspense>
</Provider>
); Fixes the problem for us for now. Hope this helps others. Looking forward to more input from @markerikson and the team. Maybe we just missing something here? |
Hmm. I know there's some nuances in the internal timing and calls to cleaning up Maybe |
What version of React, ReactDOM/React Native, Redux, and React Redux are you using?
What is the current behavior?
Additional note: This works correctly with react v17 (ReactDOM.render) and breaks in v18 (createRoot). I have also debugged the behavior and have seen that the Provider component is unmounted which removes the store subscriptions of the useSelector hooks. After the Provider mounts again, the subscriptions are not restored because the child components do not render again.
What is the expected behavior?
The number is increased on every click.
Which browser and OS are affected by this issue?
all
Did this work in previous versions of React Redux?
The text was updated successfully, but these errors were encountered: