React Hooks Tutorial – 11 – useEffect with incorrect dependency
![*](https://i0.wp.com/allprowebdesigns.com/wp-content/uploads/2023/12/1704008516_maxresdefault.jpg?resize=840%2C430&ssl=1)
Video Title: React Hooks Tutorial – 11 – useEffect with incorrect dependency
Alright guys in this video we are going to take a look at another example this time highlighting a common mistake beginners such as ourselves are likely to make and this is even more relevant to you if you’re learning hooks with knowledge of class components let’s begin for this example we are going to
Create a simple counter but this time it is going to automatically increment every second let’s quickly go through the class component implementation of an interval counter you can see that I have a file called interval class counter dot j s first in the constructor we create a state variable called count initialized
To zero next we need to create an interval timer that is going to update the count value by one the police to create timers is component dead mount so I have created an interval timer that runs every second and every second we execute the tick method the tick method
Basically increments the count value by 1 so every second the counter increments in value by one timers also need to be cleared to avoid memory leaks which we do so in component will unmount finally in the render method we display the count value this dot state dot count
If we include this component in AB guess and take a look at the browser you can see that the count value increments every second now let’s go back and implement the same with functional components and hooks I’m going to create a new file called interval hook counter dot j s
Within the file I’m going to use the snippet RFC II to create a functional component first step is to create a state variable so import you state and create a variable called count initialized to 0 and we also render this state variable in the browser
The next step is to set up our timer and you can see that we need to replicate component dip mount and the tick method let’s start with this tick function Const tick is going to be an error function and within the body we call said count passing in count plus one
Next we use effect to replicate compare indeed mount and we’ve already learned how to do that import use effect which is basically a function call plus in an arrow function and within this function we set up our timer Const interval is equal to set interval we need to call the tick method every
Second have this effect is going to fire after every render if we only want the interval to be set up once on initial render that is component dead mount equivalent we simply pass an empty array as the dependency list and that is the second parameter an empty array the
Final step is to replicate component will unmount for the cleanup so from use effect we return a function and within that function we clear the interval let’s save this file and include it in Abdo chess if you now take a look at the browser you can see that the class counter is
Working as expected but the hook counter is displaying the value of one and not incrementing every second let’s try to figure out the problem in our mind the problem statement is simple create an interval once and destroy it once so created in component did mount and destroyed in component will unmount if
We take a look at the hook counter we have definitely translated that empty dependency list so the timer is set only once and return function to destroy the timer that we have created why then doesn’t our counter work as expected the problem here is our mental
Model and I’m going to quote from Dan’s article if you think dependency array is a way to specify when you want to rerun the effect they’re going to run into problems instead dependency array should be thought of as a way to let react know about everything that the effect must
Watch for changes so our mindset was to simply replicate component did mount however by specifying an empty array we have basically told react to ignore watching for changes in the count variable suriak goes like hey on initial render the count value is 0 which implies set count will set it to 0 plus
1 which is 1 and I will render that in the browser now view are telling me that I don’t have to watch for changes in the count value count value is 1 right now and I will just render that value through the different rerender cycles if
You want me to watch a variable just add it to the dependency array what I am trying to say here is that it is a common beginners mistake to leave out the dependency list if we now add count as a dependency and take a look at the browser
You can see that we get the expected result so whenever you try to specify an empty dependency list please make sure that you really don’t have any by the way for this example there is another way to get it working without the dependency list so in the tick function we use the
Second form of set count we get access to previous count and we set previous count plus one now since set count keeps track of the previous count value we don’t have to specify count as a dependency for this particular effect save the file and take a look at the browser
You can see that the counter still works now if your code might be different to this example so always think before specifying an empty dependency array let me also give you a handy tip in this regard sometimes you might want to call a function with a noose effect so
Function do something console dot log some prop now let’s call it with in use effect do something when you do this you look at use effect and it’s very easy to forget that some prop is a dependency some prop is used and do something which is called a noose effect but it doesn’t
Necessarily seem obvious when we take a look at use effect so what is recommended is whenever you need to call a function with in use effect just go ahead and define the function with the noose effect so I’m going to move the function inside use effect this way when
You read through the effect you’re much more likely to see that you have a prop which has to be specified as a dependency all right that is pretty much it for this example I wanted to show you guys how easy it is to make mistakes when specifying the dependency list for use effect
And one last thing I want to quickly show you which I felt did not require a separate video is about specifying multiple effects if you recollect as a motivational reason for hooks we had seen that in class components related code is split into different life cycle methods whereas unrelated code is put together
In the same life cycle methods hooks solve that it is possible to include multiple use effect calls within the same component and I’m just going to quickly show you a screenshot from the react dogs you can see that we have to use effect cards right before use effect we have
Use state corresponding to that effect we have basically grouped related code together and the code looks much more organized now so if you have multiple effects to run make sure you separate them out rather than having all the code in a single use effect alright with that
We come to the end of a series of examples that reveal different details about the effect hook starting next video let’s see how to apply what we have learned so far and learn how to fetch data from an endpoint using the effect hook thank you guys for watching
Don’t forget to subscribe and make sure to hit the bell icon to be alerted when the new videos are uploaded I’ll see you guys in the next one
-
Sale!
Wireless WIFI Repeater Extender Amplifier Booster 300Mbps
$29.99$14.99 Add to cartWireless WIFI Repeater Extender Amplifier Booster 300Mbps
Categories: Electronics, Wi-Fi Router, Wireless Wi-Fi Extender Tags: 300Mbps, 802.11N, Amplifier, Booster, Extender, mobile wi-fi booster, Remote, WIFI, Wireless, Wireless WIFI, Wireless WIFI Repeater, Wireless WIFI Repeater Extender, Wireless WIFI Repeater Extender Amplifier, Wireless WIFI Repeater Extender Amplifier Booster, Wireless WIFI Repeater Extender Amplifier Booster 300Mbps$29.99$14.99 -
Sale!
Full RGB Light Design Gaming Headset Headphones with Mic
$24.99$14.99 Add to cartFull RGB Light Design Gaming Headset Headphones with Mic
Categories: Electronics, Gaming, Gaming Headsets Tags: Design, Full, Full RGB Light Design Gaming Headset, Full RGB Light Design Gaming Headset Headphones, Full RGB Light Design Gaming Headset Headphones with Mic, Gamer, Gaming, Gaming Headset Headphones, gaming headset wireless, Headphone, Headphones, Headset, Light, Mic, Package, RGB$24.99$14.99 -
Sale!
Wireless BlueTooth Multi-Device Keyboard Mouse Combo
$39.99$19.99 Add to cartWireless BlueTooth Multi-Device Keyboard Mouse Combo
Categories: Electronics, Gaming, Gaming Keyboards, Keyboard Mouse Combos Tags: Combo, Keyboard, keyboard mouse combos, Mouse, MultiDevice, Set, WireKeyboard Mouse Combo, Wireless, Wireless BlueTooth Keyboard Mouse Combo, Wireless BlueTooth Keyboard Mouse Combos, Wireless BlueTooth Multi-Device Keyboard Mouse Combo, Wireless BlueTooth Multi-Device Keyboard Mouse Combos$39.99$19.99 -
Sale!
High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar
$199.99$139.99 Add to cartHigh Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar
Categories: Gaming, Gaming Chairs Tags: Adjustable, Chair, computer chairs, Desk, Executive, Gaming, Girl, Headrest, High, High Back Leather Executive Adjustable Swivel Gaming Chair, High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest, High Back Leather Executive Adjustable Swivel Gaming Chair with Headrest and Lumbar, High Back Leather Executive Adjustable Swivel Gaming Chairs, Leather, Lumbar, Office, Racing, Swivel$199.99$139.99 -
Sale!
Professional LED Light Wired Gaming Headphones with Noise Cancelling Microphone
$29.99$19.99 Select optionsProfessional LED Light Wired Gaming Headphones with Noise Cancelling Microphone
SKU: N/A Categories: Electronics, Gaming, Gaming Headsets Tags: Cancelling, Gaming, Gaming Headphones with Noise Cancelling Microphone, gaming headset, Headphones, Headset, LED, Light, Mic, Microphone, Noise, Professional, Professional LED Light Wired Gaming Headphones, Professional LED Light Wired Gaming Headphones with Noise Cancelling Microphone, Wired, Wired Gaming Headphones, Wired Gaming Headphones with Noise Cancelling Microphone$29.99$19.99 -
Sale!
Gaming Desk with LED Lights USB Power Outlets and Charging Ports
$349.99$249.99 Select optionsGaming Desk with LED Lights USB Power Outlets and Charging Ports
SKU: N/A Categories: Computer Desk, Gaming, Gaming Desk Tags: and Charging Ports, Charging, Desk, Desks, Gaming, gaming desk with led lights, Gaming Desks with LED Lights, Home, LED, Lights, Monitor, Office, Outlets, Port, Power, Room, Stand, USB, USB Power Outlets, White, Workstation$349.99$249.99 -
Sale!
Wired Mixed Backlit Anti-Ghosting Gaming Keyboard
$99.99$79.99 Add to cartWired Mixed Backlit Anti-Ghosting Gaming Keyboard
Categories: Electronics, Gaming, Gaming Keyboards Tags: Antighosting, Backlit, Blue, brown, Gaming, Gaming Keyboard, gaming keyboards, gaming keyboards and mouse, Keyboard, Laptop, Switch, Wired, Wired Mixed Backlit Anti-Ghosting Gaming Keyboard, Wired Mixed Backlit Anti-Ghosting Gaming Keyboards, Wired Mixed Backlit Gaming Keyboard$99.99$79.99 -
Sale!
Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset
$119.99$59.99 Add to cartWireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset
Categories: Electronics, Gaming, Gaming Headsets Tags: 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset, ANC, Audio, Bluetooth, Cancellation, Ear, Earphone, gaming headset, Headphones, Headset, Hi-Res Over the Ear Headphones Headset, HiRes, Noise, Wireless, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Headphones, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headset, Wireless Bluetooth 5.3 ANC Noise Cancellation Hi-Res Over the Ear Headphones Headsets$119.99$59.99 -
Sale!
Wired Sports Gaming Headset Earbuds with Microphone
$19.99$9.99 Select optionsWired Sports Gaming Headset Earbuds with Microphone
SKU: N/A Categories: Gaming, Gaming Headsets Tags: Accessories, Earbud, Earphone, Earphones, Gaming, gaming headset with microphone, Headphones, Headset, IOS, Microphone, Sports, Wired, Wired Sports Gaming Headset Earbuds, Wired Sports Gaming Headset Earbuds with Microphone, Wired Sports Headset Earbuds$19.99$9.99 -
Sale!
150W Universal Multi USB Fast Charger 16 Port MAX Charging Station
$49.99$29.99 Add to cart150W Universal Multi USB Fast Charger 16 Port MAX Charging Station
Categories: Charging Stations, Electronics Tags: 150W, 150W Charging Station, 150W Universal Multi USB Charging Station, 150W Universal Multi USB Fast Charger 16 Port MAX Charging Station, 150W Universal Multi USB Fast Charger 16 Port MAX Charging Stations, 150W Universal Multi USB MAX Charging Station, 16 Port MAX Charging Station, 3.5A, Charger, Charging, Fast, laptop charging stations, Max, Multi, Port, Stand, Station, Universal, USB$49.99$29.99
if the useEffect re-renders everytime after the count is updated, then the setInterval will also re-run everytime.
Ideally the setInterval should run only once, and not for every re-renders for updates related to count.
Please correct me if I am wrong
0. const interval = setInterval(tick, 1000)
– interval – is a variable & setting it to the return value of the setInterval function
– setInterval is a built-in JavaScript function that repeatedly executes a given function (tick in this case) at a specified interval (1000 milliseconds or 1 second in this case).
1. below
setCount(count + 1)
with 'count' in dependency array
– is an alternative for below?
setCount(prevCount => prevCount + 1)
– 1. Yes….. But the later is considered a safer practice, especially in cases where you might have multiple state updates or asynchronous updates occurring in close succession.
—- 2. so instead of adding in dependency array, can i always use prevValues while setting? 3. Then there is no need for putting anything in dependency array right?
2. Yes, you're correct. If you consistently use the prevValues approach when setting state using the updater function, you can often avoid adding dependencies to the dependency array. This is because the prevValues approach ensures that you're always working with the most up-to-date value of the state, regardless of whether it's the initial render or a subsequent update.
3. However, there might be scenarios where you want the effect to be triggered ("API calls") based on certain state changes. In such cases, you would still need to include those relevant dependencies in the dependency array. But for cases where the "effect is meant to update the state itself", using the prevValues approach can often eliminate the need to include dependencies in the array.
– Can write functions inside useEffect:
Benefit: Encapsulation, proper coding
useEffect(() => {
const incrementCount = () => {
setCount(prevCount => prevCount + 1);
};
const interval = setInterval(incrementCount, 1000);
return () => {
clearInterval(interval);
};
}, []);
– Can have multiple useEffects inside a component.
Correct me if I am wrong….
1=> In the first case for IntervalHookCounter when dependency array is empty then setInterval is calling tick function every 1 second but since the useEffect doesnot have any dependency (i.e empty list [ ] ) the count increments in the background which is local to setInterval ……..
2=> In the second case when we mention count as dependency , the useEffect is called every time whenever the count value is updated and hence every time cleanup function is also called …it simply means u are setting and clearing the interval every 1 sec
3=> FInally the correct way ,setInterval calls tick to update count value by fetching the lastest snapshot value of count and therefore react renders here this count value, setInterval from the first time useEffect was called is responsible for incrementing the count state variable (ofcourse only once useEffect was called).
What i learned from #11
1. First of all useEffect is also a function which takes 2 parameter and 1st parameter is arrow func. and 2nd parameter is dependency list i.e array [ ].
2. to make useEffect works perfectly for this particular example Biswas earlier said that useEffect does not rendors when the count in the dependency list is same. i.e it only rendors only when [count] value is different. That's why we ensure that it's value is changing every sec and add it on the array.
3. Another way to do so is the use of PrevCount
4. function can be defined within useEffect
5. Single components can have multiple useEffect
isn't that enough for this EP11
If i want to use dosomething somewhere else as well, why have we added that in useEffect?
Can we pass multiple items in the dependency array. like [count, someProp] ? I mean if we want to execute same function in useEffect() for multiple dependencies, can we do it ? or do we need to create another useEffect() for other dependency ?
i didn't understood this video.
The console logs below give one 'effect ran', followed by one 'tick ran' per second, which is what we want.
setCount(count+1) doesn't update the browser because tick() is remembering the zero from when it was created and just running setCount 0+1) every second.
Adding count into the Effect hook does fix the browser updating, but I don't think it's a correct solution. The console logs show that it's actually clearing and reinitialising the Interval every second. In fact if you remove the return then you see the logs go crazy with multiple intervals piling up.
The correct solution here is to use setCount(prevCount => prevCount+1)
import React, { useState, useEffect } from "react";
const IntervalHookCounter = () => {
const [count, setCount] = useState(0)
const tick = () => {
console.log('tick ran')
// setCount(count + 1)
setCount(prevCount => prevCount + 1)
}
useEffect(() => {
console.log('effect ran')
const interval = setInterval(() => tick(), 1000)
return (() => {
console.log('effect removed')
clearInterval(interval)
})
}, [])
return <div>{count}</div>
}
export default IntervalHookCounter;
this example is so bad that it is actually good! I had to debug it thoroughly and discovered the fact that cleanup callback is called not only on unmount but on each effect before running a new one. But as many others mentioned as well, the issue was in the closure, not in dependency array)
The setInterval function within the useEffect hook continues to run even though useEffect only runs once because setInterval is a timer function that runs asynchronously in the background, separate from the React render cycle. Once the setInterval is set, it continues to run until it is cleared, regardless of whether the useEffect hook runs again or not.
In this case, the useEffect hook is responsible for setting the setInterval, but it only runs once, when the component is first mounted. The setInterval function continues to run in the background, updating the state and triggering re-renders, even after the useEffect hook has completed its initial run.
I feel like the explanation isn't correct at all?
Honestly, this is the first tutorial from that I really feel confused.
When you left dependency array empty the counter was not incrementing but when you use function as argument to setCount, the count increment why is that ?
Also, if you specify count in the dependency list, then whenever the count changes, the use effect will rerun, but we don't want it to rerun because we want the setInterval to run only once.
Honestly I don't feel like I understood it well, I think the idea behind the count not being incremented is related to closures when tick arrow function create a closure and keep the stale value of count and because dep list is empty the value of count will not looking for any change to its value and it stucks to 1
Excellent explanation! Thank you very much
very helpful! big thx!
Hello Vishwas, in this example why interval is not part of state?
Please make video on Virtual Dom in React
pls just simplify your explanations. too complex explanations there's irrelevant topics that are being discussed
thank you thank you thank you so much
What if we don't clear interval , anyone plz explain output? I am not understanding why even after clearing interval time is running
Can someone please confirm or correct my understanding of the issue
The counter value does not update because reactjs executes the Counter function during every render causing new state variables to be created and initialized to the stored or initialized value
So the order of execution would be
– counter value set to 0
– render done
– useEffect callback is called
– setInterval registers tick function with lexical scope of current counter variable i.e 0
– after first second, the tick function increments the state value of counter to 1
– the Counter function executes again creating a new lexical scope with counter equal to 1,
– new value is rendered
– after the next second, the tick function uses the stale lexical scope with counter = 0 and sets value of counter again to 1
– this happens because the useEffect callback won't be called this time and the setInterval callback won't receive the updated lexical scope with counter set to 1
i have a question then why x and y in last video updated ?
Do you have a discord server for this YouTube channel?
Hey, Vishwas… Can you make a Video series on Angular… There are no good Angular tutorials on youtube… Please provide us with some good Angular material.
Btw the "count" in the returned timer callback is part of the timer() lexical scope. It is not the same as the outer count. If it were, when the class component example worked while the functional component example failed, it would have implied that state had two values simultaneously, which would cause the universe to implode. Have a lovely day 🙏🏽☮️
For anyone that's confused, a simple way to understand this is that setCount(count + 1) doesn't actually update count! To see this, just do the following:
const [ count, setCount ] = useState(0);
setCount(count + 1);
setCount(count + 1);
console.log(count);
From the above code, you would expect the console.log(count) to return count = 2, but it returns count = 1!
This is not a bug, it's a feature. React makes sure that the way in which you actually alter the state is well controlled, so that you don't mutate state when it's not advisable. Further, react computes state mutation based on the previous render at the beginning of the next render cycle, so you need to wait until the next loop (or view jsx output) to see your changes to count. If you really what to change the state in the middle of a render, you do: setCount(prevCount => prevCount + 1)
So, now:
const [ count, setCount ] = useState(0);
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1);
console.log(count);
actually prints count = 2, which is what you'd expect.
What does this have to do with the original problem?
setInterval() is sent to the browser as a closure (i.e. a function + its lexical scope). Well, its lexical scope includes count = 0. When we run tick(), the function never changes the value of count within the local execution context, so as we saw from above, the state is never actually updated. For the state to be updated, tick() would need to persist between renders, which of course, it doesn't. Every time you re-render a component, you recreate the things within.
Hope this helped someone 🙂
The instructor is only partially correct. Allow me to explain.
Every time you change ANY state, your component will re-render. And Javascript waits for no-one! This means that if you have an async function within the useEffect, it may take some time to complete, and yet, the useEffect in that render gets executed, popped off the call stack, and is gone forever. Put differently, if we had to wait for that useEffect to finish its business with ANY async function, your app would freeze, waiting in anticipation.
So, really, the useEffect runs synchronously, and when it hits the async function setInterval, it simply dispatches the callback to the browser, which then keeps track of the timer. Javascript and useEffect move on with their lives! But if that's the case, how does the setInterval callback know what value of count to reference when the browser finally returns it to JS via the event-loop? Simple, the callback function is sent to the browser as what's known as a CLOSURE. Feel free to read about closures.
In summary though, a closure is just a function with the lexical scope of its parent(s). So in this case, setInterval is exported to the browser as a closure with a lexical scope that defines count (at the time the closure was created!) as being 0 i.e. count = 0. So when the callback is eventually returned from the browser to React, the tick function runs in the context of count = 0. Thus, from tick, count = count + 1 leads to count = 1… which is the expected change of state. So far so good.
But now the problems begin.
The useEffect doesn't run ever again! So we already know that 1000 milliseconds later, when the browser returns result of the setInterval callback, it's using a stale closure, with the old value of count = 0. That's precisely what went wrong. So the instructor then destroys the old timer with the return cleanup function from the useEffect, and creates a NEW setInterval function, which ofc has the updated lexical scope including count = 1.He does this by adding the count dependency. That fixes things, but it's not intuitive, it's not in the spirit of the logic, it requires us constantly add and remove event listeners, and finally, count is never explicitly referenced in useEffect(), so some people (and likely typescript) would complain that this is a "warning" error. Typically, the dependency array is used to fire a useEffect when something is directly referenced in the hook body.
So the second method is better. With it, the useEffect only runs once (minus un-mounting at the very end), only one event listener is ever created, and we constantly modify the lexical scope of the count state. Some things are best demonstrated in code than explained via text, but for those that understand closures and the event loop, now you have at least a better idea of what's really going on here.
When I first learned React a few months ago, I came across this "logical bug", and realizing that the async function had a static lexical scope made all the difference to me. Hopefully it helps you out or at least gives you something to think about 🙏🏽☺️
This vscode theme is amazing, it can tansfer => to an actual arror?I know nothing
Hi Vishwas, it is vey confusing to understand. Please explain if you could for this comment. If I am specifying counter in dependency array of useEffect, then the setInterval(tick,1000) will run times when useEffect runs. Now comparing with class's componentDidMount ,setInterval will run only once. So is it okay that setInterval runs multiple times in function component. I don't think it is okay.
what is the difference between rendering and mounting? 🙂
Prop wli baat smj ni aee…
What's the reason behind creating and then destroying the INTERVAL??
6:25 adding count to the dependency list is 100% wrong sry.
05:00 QUOTE: If you think dependency array is a way to specify when you want to rerun the effect, you are going to run into problems. Instead, dependency array should be thought of as a way to let react know about everything that the effect must watch for changes.
when incrementing the counter using hooks by passing counter in dependency array the counter speed lagging behind and mismatched after sometime when compared to the counter using class… as I have both classcomponent and hookcomponent on App.js to render simultaneously so it should be same……………while using the same hook component but this time increasing the counter with previouscounter like setCounter(previousCounter => previousCounter + 1) without counter in dependency array….the counter matched for both class based and hook based.
@Codevolution as I mentioned in the thread to Simone Galli's comment as well, it would make a lot of sense to remove / alter / reupload this video or at least add an annotation for context, as the current explanation provided is highly confusing and the suggested solution is a hacky buggy workaround to the underlying issue.
Putting [count] in the useEffect dependencies causes a new interval to be created every second. This may result in the correct update, but is baaad. The issue when having [] as second argument is not that the effect function is called at the wrong time or whatever, but just that the setter in the tick function updates the value based on an outdated reference to count.
Why after leaving it to tick for a long time, does the hook component go slower than the class component, even though they are ticking at the same interval?
what is the use of clear interval we are not stopping counter
So far, you are King !!!
this video: errors during using useEffect
It is better to include functions in the function useEffect
Multiple useEffect in one component
a simple question. why we have to type: clearInterval(interval) in the return function inside the useEffect?? what is the logic behind that in the running counter. since we have n btn to clear the counter or to reset it.