问题
I have an action and reducer that updates a global counter. This action is fired on a rapid interval. The reducer returns a new copy of the state for each action. The reducer looks like:
import { handleActions } from 'redux-actions';
import { sceneTick } from './actions';
export default (state, action) => handleActions({
[sceneTick]: (state, action) => {
return {
...state,
loop: action.payload,
}
},
I am using react-redux
's connect
method on various React components. Not all the components care about this loop counter. Because I am returning a new state in the reducer on each tick, all components subscribed with connect
get their mapDispatchToProps
executed which causes unnecessary React render calls.
One of these componets looks like:
const mapStateToProps = (state, props) => {
return {
viewport: state.viewport,
assets: state.assets,
};
};
export default connect(mapStateToProps, {})(Component)
Even though this component has no dependency on state.loop
it gets triggered to re-render. This causes re-rendering, over rendering, multiple rendering, unnecessary rendering, performance issues and unexpected behavior in components that need not re-render.
Update
I should also maybe add that I am not using combineReducers
here and all reducers are applied to the full state. Not sure if relevant.
回答1:
According to Redux implementation, connect
is pure and hence does a shallow comparison of the props that it needs to provide to the component i.e it implements a shouldComponentUpdate
method in its implementation and doesn't trigger a re-render for the connected component if the data returned from mapStateToProps
doesn't change.
It is important for Redux to monitor the state change for every change because then only it can take a decision whether to update or not.
Since a Pure component does a shallow comparison of state and props, you should make sure that your states are not highly nested
回答2:
Redux connect
accepts a areStatesEqual
function option that can be used to narrow down equality checks to specific state branches.
export default connect(
{},
{},
null,
{
areStatesEqual: (next, prev) => {
return (
prev.branch === next.branch
);
}
}
)(Component);
回答3:
If it is a performance issue due to redux, use react shouldComponentUpdate
method.
https://reactjs.org/docs/react-component.html#shouldcomponentupdate
Update: CombineReducers would make a difference. Try changing
return {
...state,
loop: action.payload,
}
to
state.loop = ...action.payload;
return state;
If you don't want to mutate the state, you should use combineReducer with loop as its own reducer. Since you weren't using combineReducers, I turned the state into the rootReducer. Its similar to what the redux author does with combineReducers (video) with the exception that the nextState was created within the combineReducer.
来源:https://stackoverflow.com/questions/48017252/how-to-limit-react-redux-connect-update-re-renders-to-specific-state-branches