Interact and Update State in React with useState

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

Social Share Links

Send Tweet

In this lesson, we'll create a Stopwatch component that will store the current time in its state. We will then have the DOM display the current time as the state is updated.

We'll cover:

  • React's useState hook
  • Setting a reference to an interval using React's useRef
  • Creating a handleRunClick function that handles flipping the running state plus creating and clearing an interval
  • Using the useEffect hook to clear the interval when the component unmounts

Instructor: [00:00] I have the static stopwatch that shows me the amount of time that has lapsed. I have a Start and a Create button. Let's go and make this dynamic. The first thing I'm going to do is I want to make the stopwatch component render some JSX that represents the state of the component.

[00:14] The state is going to be in this lapse amount of times, we'll say lapse and we'll initialize lapse to zero. Then, we also need running state. We can switch between Start and Stop, so we'll say running. If it's running, then it should say Stop, otherwise it should say Start.

[00:33] Then, we can say running is false. Of course, that's all wired up properly. Let's go ahead and get ourselves the useState hook, and lapse is now going to be useState. We'll initialize that to zero.

[00:48] That's going to return as an array with the first item is the state and the second item is an updater of the state, so that'll be setLapse. Then, on running we'll do the same thing. We'll say useState, we initialize that to false. Then, running will be the first item of that array that's returned and sub running will be the second item of that array.

[01:08] Of course, that's all wired up properly. We can initialize it to a 100 milliseconds, or we can initialize it to running is true, and we're all set there. Next, let's go ahead and make this interactive, so we can call these setLapse and setRunning update our functions as the user interacts with our component.

[01:25] On this Start and Stop button, I'm going to say onClick handle run click, and we'll make it that a function handleRunClick. Here, we'll simply say setRrunning not running. We'll toggle the running state, so I can click on Start and it turns to Stop, I can click on Stop and turns back the Start.

[01:43] Next, let's go ahead and start the stopwatch. Here I'll say, if it's running, then we'll do something, so actually need to stop it. Otherwise, we'll get our startTime which will be date.now minus the lapse.

[02:00] Then, we'll set interval. We'll setInterval to zero which means it will call this callback as quickly as possible it can. Then, we'll call setLapse date.now minus the startTime.

[02:14] If I hit Start, the stopwatch is going to go. If I hit Stop, it does not stop. Let's go ahead and make it stop. What we get back from setInterval is an intervalId. I need to store the intervalId, so that we can clear the interval.

[02:26] In this case, we'll call clearInterval. We need to pass it the intervalId. What we're going to do is we're going to pull and useRef here. I'm going to get my intervalRef. We'll just call useRef. We'll initialize it to No.

[02:43] Then, when we call setInterval, we'll just say intervalRef.current equals setInterval. Then, when we click that stop button, we can say clearInterval intervalRef.current.

[02:56] Now, I can click Start and Stop, Start and Stop. If I hit Start and Clear that's not working. Let's wire that up. Here down in my button, I'll say onClick handle clear click. We'll make that a function called handleClearClick. It will take no parameters.

[03:15] We'll simply clearInterval, intervalRef.current. We'll set the lapse to zero and setRunning to false. Great. We had Start, Stop, Clear, and Start, and Clear. One last thing that we should do to optimize this component is, if we hit the Start button, and this setIntervals being called as frequently as it possibly can.

[03:40] Then, the component is unmounted. This setIntervals cannot continue to go. We need to make sure that we clear the interval when this component is unmounted. What we're going to do is we're going to use effect, pull that useEffect, hook in here, and we'll useEffect.

[03:56] We actually don't need to do anything when this component is mounted. We just need to do something when the component is unmounted. I'm going to pass an empty array as the second argument. Make sure that this callback function is only run one time and that is returned, cleanup function is also only run one time when the component is unmounted.

[04:17] I'm going to call clearInterval intervalRef.current, and that should get us all set to be able to Start, Stop, Clear, and have a Start, and have a unmount and clear the interval when it's unmounted.

[04:31] In review to write out the stopwatch, we first took this JSX, made it represent the state of our component. Then, we created the state of our component using useState. We wired up our buttons to these functions that took care of the logic for the stopwatch component.

[04:46] We have to keep track of the intervalId. We created an intervalRef that we use to manually set the current value to this setInterval ID. We were able to clear that interval if the user hit Stop, or if they hit Clear, or if the component is unmounted using the useEffect hook with an empty array and returning a cleanup function.