As described in Reducers, a Redux reducer function:
(previousState, action) => newState, similar to the type of function you would pass to
Math.random(). This also means that updates should be done in an "immutable" fashion, which means always returning new objects with the updated data, rather than directly modifying the original state tree in-place.
Note on immutability, side effects, and mutation #
Mutation is discouraged because it generally breaks time-travel debugging, and React Redux's
- For time traveling, the Redux DevTools expect that replaying recorded actions would output a state value, but not change anything else. Side effects like mutation or asynchronous behavior will cause time travel to alter behavior between steps, breaking the application.
- For React Redux,
connectchecks to see if the props returned from a
mapStateToPropsfunction have changed in order to determine if a component needs to update. To improve performance,
connecttakes some shortcuts that rely on the state being immutable, and uses shallow reference equality checks to detect changes. This means that changes made to objects and arrays by direct mutation will not be detected, and components will not re-render.
Other side effects like generating unique IDs or timestamps in a reducer also make the code unpredictable and harder to debug and test.
Because of these rules, it's important that the following core concepts are fully understood before moving on to other specific techniques for organizing Redux reducers: