-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
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
Connected child component receives state updates earlier than the props computed from state by a parent connected component #1415
Comments
This definitely isn’t related to asynchronous dispatches, middleware, or Redux Thunk. By default, React batches updates that happen during an event handler. This is why dispatching inside a click handler does not cause the problem. So in fact However if you dispatch from a network request callback or an interval, React has no knowledge of when “related updates” might happen so each I’m not sure if this is something we can solve in React Redux easily. If you rely heavily on this style of connecting, there is a workaround: you can force React to batch the updates. setTimeout(() => {
ReactDOM.unstable_batchedUpdates(() => {
dispatch({
type: 'CHANGE-STATE'
});
});
}, 2000); As you can see this in an unstable API but it solves the problem. You can also use something like import { createStore } from 'redux';
import { batchedSubscribe } from 'redux-batched-subscribe';
import { unstable_batchedUpdates as batchedUpdates } from 'react-dom';
const store = createStore(
reducer,
batchedSubscribe(batchedUpdates)
); There may be better ways of addressing this but I am not aware of them. |
Let’s discuss this in reduxjs/react-redux#292. |
Issue: asynchronous actions trigger re-render in non-deterministic order which causes some components to be in a bad state.
Example:
https://jsfiddle.net/chandlerprall/do2mnLr3/8/ (watch console)
undefined
Breakdown:
When using the thunk middleware to asynchronously dispatch an action the mounted components are not rendered top-down but instead the listeners are processed in the order the components mounted (in the example above InnerComponent is mounted before OuterComponent).
If a property is pulled from the state and passed into another connected component that listens for a separate state value, the component re-renders with the old property but new state which can be out of sync. This is mitigated in synchronous dispatches because of how React enqueues pending changes, but could break in the same way if
setState
is changed to a true asynchronous model.Walkthrough:
(the example demonstrates a split-store approach where a Page Level store would track the IDs of content to show and the content is stored separately, mapped by ID)
shouldComponentUpdate
returns true and InnerComponent uses an old key (‘lorem’) which is no longer valid in the store.shouldComponentUpdate
returns true as the incoming property changed, it now uses the up-to-date textKey to pull from the content store and renders correctly.Again, this issue is avoided when the dispatch happens synchronously because setState isn’t asynchronous, but from the ReactJS docs:
There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.
This may be a bigger issue in the future, affecting all operations.This may belong in the react-redux project instead, if so I’ll gladly move it over there.
The text was updated successfully, but these errors were encountered: