What is a Redux Reducer in React?
This article provides a comprehensive overview of Redux reducers in React. It explains their fundamental role in state management, how they process actions to update the application state, the importance of keeping them as pure functions, and provides a practical code example to help you implement them in your projects.
Understanding Redux Reducers
In Redux, a reducer is a JavaScript function that determines how the application’s state changes in response to an action sent to the store. Reducers act as the “deciders” in the Redux state management flow. They receive the current state and an incoming action, process the payload, and return a brand-new state object.
The fundamental formula of a reducer is:
(state, action) => newStateHow Reducers Work
To manage state predictably, Redux relies on a unidirectional data flow. Reducers sit at the center of this flow.
- An Event Occurs: A user interacts with the UI (e.g., clicks a button).
- An Action is Dispatched: The UI dispatches an
action—a plain JavaScript object that describes what happened (e.g.,
{ type: 'INCREMENT' }). - The Reducer Runs: Redux passes the current state and the dispatched action to the reducer.
- State is Updated: The reducer calculates the new state based on the action type and returns it.
- The UI Re-renders: The React components subscribe to the store, detect the state change, and re-render with the new data.
Key Rules of Reducers
To ensure predictable behavior and enable features like time-travel debugging, Redux reducers must adhere to two strict rules:
1. They Must Be Pure Functions
A reducer must be a pure function. This means: * Given the same arguments, it must always return the exact same result. * It must not cause side effects. This means no API calls, no routing transitions, and no modifications to variables outside the function scope.
2. They Must Not Mutate State Directly
State in Redux is read-only. A reducer must never mutate the existing
state object directly. Instead, it must create a copy of
the existing state, make changes to the copy, and return that new copy.
Developers typically use the JavaScript spread operator
(...) to achieve this.
A Practical Code Example
Here is a simple example of a reducer managing the state of a counter application:
// Define the initial state of the application
const initialState = {
count: 0
};
// The reducer function
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'counter/incremented':
// Return a new state object with the updated count
return {
...state,
count: state.count + 1
};
case 'counter/decremented':
return {
...state,
count: state.count - 1
};
case 'counter/setAmount':
return {
...state,
count: action.payload
};
default:
// If the action is not recognized, return the current state unchanged
return state;
}
}In this example, the counterReducer checks the
type property of the dispatched action. If the action type
matches one of the cases, it returns a new state object. If the action
type does not match, it returns the current state untouched, ensuring
the application does not break.