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.
React limits the number of renders to prevent an infinite loop" occurs for multiple reasons: Calling a function that sets the state in the render method of a component. Immediately invoking an event handler, instead of passing a function. Having a useEffect hook that sets and re-renders infinitely.
React schedules a render every time the state of a component changes. Scheduling a render means that this doesn't happen immediately.
React-redux component does not rerender on store state change.
dispatch(action) Dispatches an action. This is the only way to trigger a state change. The store's reducing function will be called with the current getState() result and the given action synchronously.
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);
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With