← Back to React Course | Chapter 9: State Management | Lesson 5 of 10

Store, Actions, and Reducers

Actions and reducers are like order tickets in a restaurant kitchen — the ticket (action) says what was ordered, and the chef (reducer) is the only one allowed to actually prepare the dish (update the state).
Syntax
markup
// 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.

Note: A common convention is 'domain/eventName' for type strings, like 'cart/addItem' or 'auth/login', to avoid collisions between unrelated actions.
Warning: Actions only describe what happened — dispatching one doesn't change anything by itself until a reducer handles it.

Example: Anatomy of an Action

markup
// 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.

Note: Use a switch statement (or an if/else chain) on action.type to decide which piece of logic to run.
Warning: Forgetting a default case that returns the unchanged state means an unrecognized action type could return undefined, corrupting the store.

Example: Anatomy of a Reducer

markup
// 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.

Note: Redux DevTools lets you literally see every dispatched action and the resulting state change, which is invaluable for debugging this flow.
Warning: Nothing in this cycle updates the UI directly — components only re-render because they're subscribed to the store via useSelector, reacting to the state change.

Example: The One-Way Data Flow

markup
// 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
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Giving two different actions the same type string, causing one to accidentally trigger the other's logic.
  2. Putting side effects (API calls, timers) directly inside a reducer instead of in middleware or a component.
  3. Returning undefined from a reducer's default case instead of returning the unchanged state.
Chapter Summary
  • 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.
Browser Support

Requires npm install redux (or @reduxjs/toolkit) — not available via CDN in this sandbox.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.