Store, Actions, and Reducers
In this page:
// Action: a plain object
{ type: "domain/actionName", payload: data }
// Reducer: (state, action) => newState
function reducer(state = initialState, action) {
switch (action.type) {
case "domain/actionName":
return { ...state, key: action.payload };
default:
return state;
}
}
Anatomy of an Action
An action is just a plain JavaScript object with, at minimum, a type field — a string describing what happened, like 'cart/addItem'.
Any additional data needed to process that action (like which item was added) is usually included as a payload field.
Example: Anatomy of an Action
// Run in your local React project (npm install required)
const addItemAction = {
type: 'cart/addItem',
payload: { id: 1, name: 'Book' },
};
store.dispatch(addItemAction);
Anatomy of a Reducer
A reducer is a function taking the current state and an action, and returning the next state. It must be pure — given the same inputs, it always produces the same output, with no API calls, no mutations, and no randomness.
Example: Anatomy of a Reducer
// Run in your local React project (npm install required)
function cartReducer(state = { items: [] }, action) {
switch (action.type) {
case 'cart/addItem':
return { items: [...state.items, action.payload] };
default:
return state;
}
}
The One-Way Data Flow
Redux enforces a strict cycle: a component dispatches an action, the reducer computes new state from it, the store updates, and any component reading that state re-renders with the new value.
This predictable, one-directional flow is what makes Redux apps easier to debug and reason about.
Example: The One-Way Data Flow
// Run in your local React project (npm install required)
// 1. Component dispatches:
dispatch({ type: 'cart/addItem', payload: { id: 2, name: 'Pen' } });
// 2. Reducer computes new state (shown above)
// 3. Store updates internally
// 4. useSelector(state => state.cart.items) re-runs in any subscribed component
// 5. That component re-renders with the new items array
- Giving two different actions the same type string, causing one to accidentally trigger the other's logic.
- Putting side effects (API calls, timers) directly inside a reducer instead of in middleware or a component.
- Returning undefined from a reducer's default case instead of returning the unchanged state.
- An action is a plain object with a type field describing what happened, plus optional data (the payload).
- A reducer is a pure function: (state, action) => newState, with no side effects.
- The store's dispatch(action) function is the only way to trigger a state update.
- Reducers must always return a value, including an unchanged state for actions they don't recognize.
Requires npm install redux (or @reduxjs/toolkit) — not available via CDN in this sandbox.
Chapter Quiz — Complete all 10 topics to unlock
0/10 topics done
Complete these topics first: