From the course: React: Advanced Code Challenges
Preventing useEffect infinite loop - React.js Tutorial
From the course: React: Advanced Code Challenges
Preventing useEffect infinite loop
- [Speaker] useEffect is a react hook that lets you perform side effects in your functional components. Side effects such as fetching data, subscribing to external services or system, updating the DOM, the document object model, or setting up a timer, which is one example we're going to look at next. As a quick reminder, let's look at the useEffect syntax. So the useEffect hook takes two parameters. The setup first, then the list of dependencies, which is an array, and the useEffect hook runs after render, but also depending on the state change, depending on the list of dependencies. And with useEffect, the potential problem is if by mistake, you update the state inside the effect and that the state is also listed as a dependency, you may create what we call an infinite loop, which is a common mistake with useEffects. So let's take our example, which is the countdown timer, and this one is a broken example. We're going to see why and how. Here we have the CountdownBroken components, we define state variables and we start an interval inside the useEffects. Then we're going to be able to read how much time is left. Line 12. So let's run this example. Alright, so we starts, but then it stops. Okay, so let's go back for a minute. Okay, we go back and something that you notice, line 10, we have an MTRA, meaning that the useEffect is going to run only once. So if you want to update whenever there is a state change you want to provide with a dependency inside this area, let's see what happens now. Alright, so we start again. And something we're going to do also is to check what happens actually when we open the terminal. Alright, so let's refresh again. Alright, so now, we can start the timer. It updates and we can actually see already that it updates and it renders multiple times. So what happens here, what is wrong? Every time that the count updates, the effect runs, the same effect runs the counts updates, then it renders, it updates again, then it triggers a renderer again over and over again. It is on repeats, it never stops. The cycle continues. And this is what we call the useEffect infinite loop. So how do we prevent the bad pattern of the useEffect infinite loop. So here, the first fix that we can do is to check if timeLeft is over zero, meaning that we're going to only run the interval if we are above zero, and as soon as we hit zero, we're going to stop the interval. Alright, so let's see what happens now. Let's refresh. So we're going to allow to start the timer, but then stop the timer as soon as we hit zero. All right, so let's see what happens. It's running, so far, so good, except that even if we reach zero, it's going to continue to run and it's going to render and create an infinite loop. So what else can we do? So let's go back. Something we can do also to fix the problem is to actually prevent from using the same states inside the useEffect, but also inside the list of dependency. And for that, we can use what we call a functional updates. So we're going to actually allow to update using the previous states. All right, so this is a functional update. So instead of using time left, because this is what's going to cause the infinite loop. So this way, the value doesn't need to be listed in the list of dependencies to avoid any retriggers and re-renderer. Alright, let's go back and start again. The timer starting from 10. All right. Alright, so it's still running because it looks like we have some other problems which are memo release. What we want is every time that you create a new timer, you want to clear it inside the useEffect because what we do is to create a new timer every time over and over. So instead what we're going to do is this conditional check. We're going to do it appear, we're going to check if it is equal to zero, we're going to return to stay out of the interval. And then instead of having this if statement, we're going to then remove this, create a timer like this with that interval and then we can allow to clean it. And we're going to do that to avoid any memory leaks. We're going to do that with clear interval and then past timer like this. Alright, so we have our timer running, up and running and it's going to stop as soon as it hits zero and we no longer have any rerender. So we have stopped the issue of the infinite loop. Alright, so we've been able to successfully prevent the useEffect infinite loop. So what we've done is to use the conditional check to avoid any continuous updates. We have also used the functional updates with setStates, and what's important also is to watch carefully for the list of dependencies. Something that we can use and learn also to do in order to fix any issue going on with the lifecycle updates of your React application is to minimize functions and objects. And we're going to look at other examples next.