Impure connected component aren't updated when the store changes state
See original GitHub issueFrom the docs:
[
pure = true
] (Boolean): If true, implementsshouldComponentUpdate
and shallowly compares the result ofmergeProps
, preventing unnecessary updates, assuming that the component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. Defaults totrue
.
Given this, I would expect impure components to always be re-rendered whenever the store changes, as it cannot assume that some variable it depends on outside its props or the store hasn’t been mutated. However, this does not seem to be the case as this fiddle demonstrates:
const store = Redux.createStore(() => ({}));
let impureDependency = "Initial value";
class MyComponent extends React.Component {
render() {
return <div>{ impureDependency }</div>;
}
}
const connect = ReactRedux.connect(() => ({}), null, null, { pure: false });
const MyConnectedComponent = connect(MyComponent);
ReactDOM.render(
<ReactRedux.Provider store={store}>
<MyConnectedComponent />
</ReactRedux.Provider>,
document.getElementById("container")
);
impureDependency = "Updated value";
store.dispatch({ type: "ACTION" });
The render method for MyComponent
is dependent on variable impureDependency
outside both its props and the Redux store, making it an impure component, and a connected version of the component, MyConnectedComponent
, is subsequently created on line 11. This variable has its value changed from "Initial value"
to "Updated value"
on line 20. A dummy action is dispatched to the store on line 21 (causing the store state to change as store reducers will always return a new state), at which point we’d expect MyConnectedComponent
to be re-rendered but the rendered text remains as "Initial value"
.
This is due to Connect.prototype.render()
failing to check if a component is pure before determining whether re-rendering the component can be skipped or not. The solution is to add this check so that impure components always get re-rendered.
Issue Analytics
- State:
- Created 7 years ago
- Comments:10 (3 by maintainers)
Top GitHub Comments
Yes, I’ve tested #416 and it does fix this too.
Since merging props is always shallow, the shallow equality checks are sufficient to control whether a merge needs to happen or not. It is just that for impure objects, a shallow equality check isn’t sufficient to tell whether the wrapped component should re-render.
I’d say yes, impure components should always return true from
shouldComponentUpdate
, since the props from the parent and the props from the store may have changed in a way that requires an update, even if they still match with a shallow equality comparison.The docs say that the test for pure components is against
mergedProps
rather than against eitherownProps
or the props from the store, so the fix in #429 to have impure components ignorehaveMergedPropsChanged
seems correct.Yeah the test sounds valuable. I’ll try to pull it into my fork. I’m hoping the beta release happens sometime this week, but I can’t say when it might make it to production