useReducer Deep Dive: Actions, Dispatch, and the Reducer Pattern

Hands-on practice for this lecture. Work through the exercises and quizzes to reinforce what you've learned.

1

Exercise 1 of 2

Trace the Reducer

Walk through five dispatch calls on a counter reducer. Predict the state after each action β€” including what happens with an unknown action type.

Reducer

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return { count: 0 };
    default:
      return state;
  }
}

// Initial state: { count: 0 }

Trace the state through each dispatch call.

dispatch({ type: 'increment' })

State after this dispatch?

dispatch({ type: 'increment' }) // again

State after second increment?

dispatch({ type: 'decrement' })

State after decrement?

dispatch({ type: 'reset' })

State after reset?

dispatch({ type: 'unknown' })

State after unknown action type?

0/5 answered

πŸ’‘ The default case returning state is critical β€” unknown action types should always return the current state unchanged, never null or undefined.

2

Exercise 2 of 2

Build a Todo Reducer

Live editor: implement a useReducer reducer that handles add, remove, and clear actions for a todo list β€” without mutating state.

Task

Implement todoReducer to handle three action types:

  • add β€” append { id, text } to the list
  • remove β€” filter out the item matching action.id
  • clear β€” return an empty todos array

Never mutate the existing state β€” always return a new object.

Loading editor…
Practice: useReducer Deep Dive: Actions, Dispatch, and the Reducer Pattern β€” Interactive Exercises | Durgesh Rai