Declaratively Interact with Complex Component State using the React useReducer Hook

Kent C. Dodds
InstructorKent C. Dodds
Share this video with your friends

Social Share Links

Send Tweet

Having to use useState for every item in your state quickly gets cumbersome. In this lesson, we’ll learn how to refactor our component to use useReducer instead.

We'll cover:

  • Creating an initial state with useReducer
  • Making a reducer function that makes changes to the state based on incoming dispatches

Narrator: [00:00] In more complex components, having a useState for every item of state in the component might be a little bit much, so we're going to switch from useState to useReducer. With useReducer, let's go ahead and we'll get our state and dispatch from useReducer.

[00:18] We need to provide a reducer here. I'll just put reducer and we'll make that function reducer up here and that's going to take our state and our action. Then we also want to initialize this reducer state so we'll pass a second argument that is the initial state of running as false and lapse of zero.

[00:39] Let's go ahead and just destructure this state because I don't want to type state all over my component. I'll just stay running and lapse. Destructure directly where our state was.

[00:48] Now let's go ahead and get rid of these usages of useState and we'll go to all those places that those were used. Here first we have setLaps. I'm going to use dispatch and then we'll set the type to lapse and now to Date.now and the start time to the start time value.

[01:07] Then we can go up to our reducer and handle this action type, so we'll say switch on action.type, and if the value is lapse then we can return the state with the lapse value being action.now minus the action.startTime.

[01:28] Then on our setRunning, we'll simply dispatch an action with the type of toggle(running). We'll go ahead and handle that in our reducer with case toggle(running). Here we'll return an object that has the value of state with running as the opposite of state.Running.

[01:52] Then down here, where we setLapse and setRunning we can do this in one operation with a dispatch of type as clear. We can get rid of those. Then we can grab this clear and we'll handle that case for clear as well. We'll return the state running as false and lapse is zero. For the default case we'll simply return the state.

[02:15] With that we can hit Start and Stop and Start and Clear and Start and Stop and Clear. Everything's working exactly as it was before, except now we have all the logic for our state updates inside of this handy reducer function.

[02:28] In review, to make this work, we removed the useState usages and we just used this single useReducer hook. That will give us back our state, which we destructured to running at lapse and a dispatch function, which we'll call our reducer with the state and whatever argument the dispatch is called with.