You might not need useEffect() ...

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
The useEffect hook is a pretty important and commonly used React hook, but it's also a React hook that's often used incorrectly because it's either used in the wrong way, so in a situation where you need to use it but you have an error in your code, or, and that could also be problematic, because you're using it in a situation where you actually shouldn't be using it. And I'll also say right away that, at least in my tiny small tech Twitter bubble, there's an almost religious movement about not using useEffect and how horrible it is if you are using it, and this video does not aim to be part of that movement. Instead, I want to show you what common pitfalls are when using useEffect and in which situations you might not need it. I also want to mention right away that there is an entire article on the official React docs that lists even more examples and situations where you might not need useEffect, but I also want to say right away that if you are using it in a place where you might not need it, it's not necessarily the end of the world. Should you aim to avoid that? Yes. But is it the end of the world? No, it's not. It can have a negative impact if you are using useEffect in the wrong situation, because it can potentially introduce bugs if you're then also using it in the wrong way, and it can also have a negative impact on performance, but in many applications it might also simply not matter. And there also simply are situations where in the end you do need useEffect in one way or the other, as you will also see in this video. Now I want to start with the basics. How exactly does useEffect work? Well, it is a hook, which you use in your component function therefore, and this hook takes two main arguments, a function as the first argument and an array as a second argument, though that second argument is optional and I'll get back to that. Now the idea is that this function, which you pass as a first argument to useEffect, will be executed automatically by React every time after your component function executes. So whenever your component function executes, the effect function will also execute, but only after the component function execution is done. And you can see that here where I'm logging when the component function executes and when the effect function executes, you can see here in the dev tools that I got the component function log and then the effect function log. And we're seeing two effect function logs here because this app is running in strict mode and in strict mode React essentially calls those effect functions twice because that can help you catch certain bugs in case you're doing something in that effect function you shouldn't be doing there, but that's not too important here. Instead, this is how this useEffect hook generally works. Now we also got that second argument though, this array, and that's an array of dependencies where you essentially specify all the values, all the variables, constants, props that might be used inside of this effect function. So for example here, I specified this count state constant as a dependency because I'm logging the count. And this dependencies array here works such that it basically restricts how often React will execute this effect function. Because if you would not specify this second argument, this would really execute every time the component function executes after it executed. So here where I got two pieces of state, this effect function and this code in there would also execute if this details visible state changes even though I'm not using that state in the effect function. But without that second argument, it would execute every time after the component function executed and therefore here you would see that it does now not just log whenever I click these buttons, but also when I click the show details button, we also got the effect function executing here. And that already is one way of using it incorrectly because you should always add all the things and just the things that are being used in the effect function to that dependencies array and therefore you should also pretty much always add that dependencies array unless you really want the effect function to really execute after every component function execution. Now if you add an empty array here, you would essentially get this effect function to only execute once when the component first renders because it will always be called there by React, but never thereafter because if you have an empty effect dependencies array here, you're essentially telling React that this effect does not have any dependencies, therefore those dependencies also can't change and therefore it never re-executes this function. Because React takes a look at the values you specify in that array and it checks whether those values changed and if they did change, it will re-execute the function. If they don't, it won't and therefore no dependencies, no changes, no re-executions. Here however in this example, I have a dependency. I have this count state constant. I want to output the current count and therefore if you think about that logically, it makes sense that this count should be added here as a dependency because that then ensures that this effect function will be executed by React whenever the count changed, which makes sense because I want to output the current count in there. So with count added here to this dependencies array, if I reload, you will see it executed once initially, but then it won't execute if I show or hide the details. Only the component function executes there, but not the effect. But the effect will execute if I click those counter buttons. There you can see that the effect function executed. And that's how it generally works and how you generally should use this useEffect hook. And the simple main rule is that any value, any constant or variable that gets used in there should be added to this dependencies array unless it's some constant or variable that will never change. So if I'm defining some constant outside of this component function, like hello for example, like this, then I could use this here in the effect and console.log text and I would not have to add it to this dependencies array because this constant will never change. It's not impacted by React or by those React components because it's defined statically outside of all those component functions. But if you have any value that's received as a prop or managed as state, you should add that value to that dependencies array. That's the main simple rule. Now I do dive much deeper into useEffect and React in general and show you many examples and demo projects in my complete React course, which therefore might be interesting to you and you find a link to that course below the video therefore. But these are essentially the basics you should know no matter if you're building basic or more advanced React applications. It's also worth noting that state updating functions like setCount don't need to be added to this dependencies array because those functions, despite being regular values in JavaScript, are guaranteed to never change by React. So if I'm also calling setCount here in useEffect, we don't have to add that here. We could, but we don't have to. Though now that I already added this, it's also worth noting that this is another potential problem with useEffect. If you're using it to update some state, you might be introducing some infinite loop because here, for example, I'm now changing the count and then I also have the count as a dependency of this effect. Now here in this example where I set my count to a predefined static value that's always the same, zero, I actually won't get an infinite loop. I just will get some strange behavior because I always reset the count. But if I would change my count in there by, for example, deducting something from it like this, then I would have an infinite loop as you can see here now because now my effect function would change the state on which it depends which would cause it to re-execute again and so on. So that's another common pitfall which you absolutely should avoid. You can introduce infinite loops with useEffect if you're not careful. So that's therefore how you might be using useEffect in the wrong way by either not specifying dependencies you should be specifying or by specifying dependencies that are not needed and that could therefore cause the effect to execute unnecessarily or by introducing infinite loops. These are the main pitfalls we got there. But as I mentioned earlier, that's not all. You also have situations where you might be using useEffect in situations where you actually don't need to use it. And then if you do use it in such situations, you could therefore introduce unnecessary bugs if you also have some error in your code or negatively affect performance. And here is an example of useEffect being used in a situation where you actually don't need to use it. In this topic editor component function I have two useEffect usages and in the first one here I update the selected topic state depending on some prop value which I get as an input and that's why I added it here to the dependencies. I did not add dummy topics here because dummy topics is a constant defined outside of those React components and therefore never changes with those components as I explained before. Now the problem with this first useEffect usage here is that it's redundant. I'm updating some state based on some prop value I receive and that might sound logical, right? I'm getting some selected topic id here for this demo app where I can select different topics and then open a note editor for every topic where I can take some notes and save them. So that might make sense that I want to update this state but actually we don't need that state here. That can instead be a computed value and that's one of the main ways of getting rid of useEffect. Computing a value, deriving state instead of managing separate state with useEffect. So for example here instead of having this selected topic state we can get rid of this entire useEffect call and instead derive our selected topic value here by executing this logic. So I'm still using the selected topic id here which I get as a prop value but I'm then using it to compute a new value, the selected topic right after or right when the component function executes. And there is no need to have that as a separate state here. Instead I can just derive it like this. With that change made if I save that and I reload I can still select different topics and I can still save some text for those different topics and that all works but now without that extra useEffect usage. So that's one of the main ways of getting rid of it. Computing or deriving a value instead of managing it as a separate state that's then updated with useEffect. But we can actually also get rid of the second useEffect usage here and we can get rid of it in a way that's actually pretty elegant but not known by all React developers because we can get rid of it with help of a key. Now to understand that let's take a look at what we're doing in this useEffect call here in the end. Well I'm using useEffect here to reset or update some state based on some other state, some other computed state in this case. I'm updating the entered note here which in the end is some text that is being output down there in a text area whenever that other state, the selected topic, changes. And that state or that value changes based on some prop value we're getting. And that's actually a pretty common situation that you have some state that should be reset when some prop value changes or that should be updated when some prop value changes. And if that's something you want to do then there is a pretty elegant workaround you can use because in React you can use a key to reset a component and all its state. So here we can get rid of useEffect and go to the place where we're using this component, this topic editor component, and where we're passing our prop to that component. And here we can also add the key prop. Now you might know that prop from outputting list content in React and indeed that is the most common scenario where you might be using such a key but it's not the only thing you can do with that key or not the only place where you can use such a key. Instead you can use it on any component anywhere in your JSX code even if you're not outputting list content and then whenever the value you pass to that key changes React will essentially reset the element or component on which you're using the key. So it will essentially remove and re-render that component you could say. It'll not actually do that but you'll get the same result. You'll completely reset the component on which you're using the key if the key value changes. So therefore here we could add the selected topic id as a value for the key on the topic editor and therefore every time this value changes, the selected topic id, this component will be reset. Now of course in that component I still want to output the node text that is connected to the selected topic and therefore we should tweak that code a little bit and set the initial state of entered node to our selected topic dot node and for that we should make sure that we calculate the selected topic here before we use it. Now since this component will be reset and recreated you could say every time the selected topic id changes this state will be re-initialized every time that happens and therefore will update the initial state with any node text that might be stored for a selected topic and that's exactly the result we want here. Now it's possible that we don't have a selected topic here and therefore I'll actually add this question mark to make sure that if selected topic is undefined we don't cause an error here but instead we then just set undefined as the starting state. Well and with that if we reload we can switch between those topics and I can enter some topic text here but if I then switch to a different topic you see that text was cleared. If I save it for a given topic and I switch away it's cleared but it's then recreated if I switch back to the topic where I saved it because I'm using that saved node text as my initial state here and the component is recreated essentially because of that key and that's therefore another really important tool every developer should know about because using keys to reset components and essentially recreate them you could say and therefore reset their state is super helpful and can also help you avoid use effect. So we already saw two of the most important ways of avoiding use effect computed values and using keys here's another situation where you might not need it. Here I'm using use effect to essentially initialize some state with some data I'm fetching from local storage. Now I'm doing this here for this application where I can add some items and if I reload the app those items are still there because I'm saving them in local storage and I'm initializing my state with that local storage data. This might look reasonable but you don't need use effect here because local storage is actually a synchronous API which you can simply call without use effect. You can simply call it and execute all that code before initializing your state because this is all synchronous code that executes step by step without any delay so therefore there's no need to update the state like this. Instead we can just remove this code, reach out to local storage and initialize our state with the parsed code or with the parsed to dos like this and if we want actually also provide a fallback value where we use an empty array if we don't find anything in local storage. And with that we got rid of another unnecessary use effect call. Now things change however and you do need use effect if you don't have synchronous code that's executed to get you your initial state but instead asynchronous code like here where I'm sending an HTTP request to fetch some to dos. I'm sending such a request here and I'm then setting my state my to dos state here based on the data I got back from the response and I also got some other states here to handle errors and the loading state and so on. And for situations like this where you are loading data from a backend for example so where you're sending an HTTP request and where you therefore have asynchronous code that's not finished instantly and that you can't use for initializing your state therefore in situations like this you need use effect and it's absolutely fine and not just fine but required to use it there. However you can also get rid of use effect in such situations if you want to though it'll still be used under the hood. But you can use libraries like tanstackquery which was previously known as reactquery and on which I also have a complete section in my react the complete guide course and that is a package that essentially simplifies the process of sending HTTP requests and updating your components with the response data and it also does much more than that. It caches response data so that unnecessary requests are avoided and it gives you many many awesome features and therefore I would recommend that you look into using this library if you were building a react application that needs to send HTTP requests and fetch data from somewhere and so on. It's really helpful and really an amazing library every react developer should at least try in my opinion. I also want to emphasize though and that's where I now differ from some of those people that tell you that it's always wrong to use use effect that whilst libraries like tanstackquery are super useful you don't have to use them. If you have a simple react application and you don't need response data caching or anything like that or you want to build that on your own and if it's just for practice purposes then of course use use effect for that because that library also uses use effect internally. Now it makes sense to use it because it gives you all these extra features and it can help you avoid unnecessary bugs and so on it can help you provide a better user experience but in the end if in your app you have a situation where you're fine with using use effect just use it. It is fine and it is a hook which is often used incorrectly or in the wrong situations but which isn't always wrong to be used and this video hopefully helped a bit with that.
Info
Channel: Academind
Views: 143,850
Rating: undefined out of 5
Keywords: react, reactjs, react.js, useeffect, tanstack query, react query, maximilian schwarzmueller, maximilian schwarzmuller, maximilian schwarzmüller
Id: V1f8MOQiHRw
Channel Id: undefined
Length: 21min 45sec (1305 seconds)
Published: Wed Mar 20 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.