Why calculateChangedBits = () => 0
See original GitHub issueBackground
React-Redux v6 (RR6) introduced what I’d call the state-based context value. The idea was to let React propagate re-render instead of triggering re-render from outside of React. This makes it easy to ensure components render top-down the component tree. Unfortunately, a way to bail out with useContext didn’t come, as I understand because there’s no way to implement that in an efficient way. So, React-Redux v7 (RR7) went back to store context and subscriptions.
Problem (Hypothetical)
We are not sure what the final concurrent mode will look like, but @markerikson had a comment in the code.
// TODO We're reading the store directly in render() here. Bad idea?
// This will likely cause Bad Things (TM) to happen in Concurrent Mode.
// Note that we do this because on renders _not_ caused by store updates, we need the latest store state
// to determine what the child props should be.
My understanding is if a component reads a state from the store, it might not be consistent for all components in the tree. If React pauses rendering in the middle of the tree, Redux may update the store state. So, a component A and a component B could get different state even in a single render in the tree. I was hoping batchedUpdates solves this, but unless batchedUpdates run all renders synchronously, Redux has a chance to update the store state. If we could only read a state from the context like RR6, this problem should be solved.
That doesn’t mean all issues around concurrent mode are solved. a warning comment by @gaearon .
Solution
We specify calculateChangedBits = () => 0;
so that React doesn’t propagate updates.
Only a single Provider subscribes to the Redux store. All components under the Provider subscribe to the Provider. When the store state is updated, Provider re-renders which triggers listeners, subscribed components check updates (in useSelector) and forces render. When a component re-renders, it will read the state from the context, and we expect it’s consistent. (No evidence, but that’s how RR6 would have worked.)
Note, this still doesn’t solve the stale props issue in useSelector.
Regret
If we had this solution half a year ago, we would have been able technically to base RR6 to add hooks support. (Updating peer deps might still require major version up, though.) It’s too late and this doesn’t provide any constructive suggestion now, but it may give a hint hopefully.
Final note
I read once again the 14110 issue, and found @sebmarkbage 's comment.
E.g. setting changed bits to zero and then manually force updating the relevant children.
It’s already noted. I didn’t have enough understanding back then. But, this is it.
Issue Analytics
- State:
- Created 4 years ago
- Comments:16 (8 by maintainers)
Top GitHub Comments
Huh. @dai-shi , check out this RFC for React context changes by @gnoff :
https://github.com/gnoff/rfcs/pull/2
Yeah, it would have been something to consider. Not sure if it would have been the ultimate solution, but would definitely have been worth comparing.