Lesson 5 of 7 · 12 min · 1 hands-on step
State, Events & Reducers
Manage changing data predictably, the way React's useReducer and Redux do.
State is data that changes
The items in a cart, whether a menu is open, what's typed in a search box: all state. Bugs love state, because many parts of the app can change it.
Reducers: one place for every change
A reducer is a pure function: (currentState, action) → newState. Every change in your app becomes an action like { type: "add", text: "Milk" }.
function counter(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "reset":
return { count: 0 };
default:
return state;
}
}
let state = { count: 0 };
for (const action of [{ type: "increment" }, { type: "increment" }, { type: "reset" }, { type: "increment" }]) {
state = counter(state, action);
console.log(action.type, "→", state);
}Because it's pure (same input, same output, no side effects), it's trivially easy to test, and you can replay every action to reproduce a bug.
Immutability: copy, don't change
const before = { name: "Ada", skills: ["JS"] };
const after = { ...before, skills: [...before.skills, "SQL"] };
console.log(before.skills, after.skills);
console.log(before === after); // false: React sees "something changed"React decides what to re-render by checking whether state is a new object. Change an array in place and React may not notice. That's one of the most common React bugs.
In React
const [todos, dispatch] = useReducer(todosReducer, []);
<button onClick={() => dispatch({ type: "add", text })}>Add</button>
Your reducer from the practice step would work in a real React app unchanged.
🧪 Practice
A reducer takes the current state and an action, and returns the new state (never modifying the old one).
Write todos(state, action) handling:
{ type: "add", text }→ append{ id, text, done: false }where id =state.length + 1{ type: "toggle", id }→ flipdonefor that todo{ type: "remove", id }→ remove it- anything else → return
stateunchanged
function todos(state, action) {
return state;
}
Output appears here. Press Run or Ctrl/⌘ + Enter.
✅ Check your understanding
Why must reducers return new objects instead of changing the old ones?
Create a free account to track your progress.