mediumReact Native#5

useReducer for complex state

Prompt

Implement a todo list reducer for useReducer. Support actions: ADD_TODO, TOGGLE_TODO, REMOVE_TODO. Each todo has { id, text, completed }. ADD_TODO receives { text }, TOGGLE_TODO and REMOVE_TODO receive { id }. Unknown actions must return the state unchanged.

Solution

function todoReducer(state, action) {
  switch (action.type) {
    case 'ADD_TODO': return [...state, { id: Date.now(), text: action.text, completed: false }]
    case 'TOGGLE_TODO': return state.map(t => t.id === action.id ? { ...t, completed: !t.completed } : t)
    case 'REMOVE_TODO': return state.filter(t => t.id !== action.id)
    default: return state
  }
}
Mentor's take

useReducer earns its place when state transitions outnumber the state itself: instead of three handlers each calling setTodos with ad-hoc logic, every legal transition lives in one pure function. That centralization pays twice — the reducer is unit-testable without rendering anything (exactly what these tests do), and dispatching from deep children needs only a stable dispatch, which React guarantees never changes identity.

The load-bearing requirement is immutability. map, filter, and spread each return a new array/object; React decides whether to re-render by comparing references, so state.push(...) or flipping t.completed in place returns the same reference and the UI silently stops updating. Note also that TOGGLE_TODO copies only the touched todo — untouched items keep their identity, which keeps React.memo'd rows from re-rendering.

The default: return state branch isn't boilerplate: returning the same reference for unknown actions tells React nothing changed, so no re-render happens.

Red flag: mutating state inside the reducer and "fixing" it with [...state] at the end — that copies the array but not the todos, so memoized children still see stale references. Immutability applies at every level you change.

Say it: "A reducer centralizes every legal state transition into one pure, testable function — and immutability isn't style, it's the reference-equality contract React's rendering depends on."