All useEffect Mistakes Every Junior React Developer Makes

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hello friends, let’s try to understand useEffect  and how it works, and talk about the most common   useEffect problems. You might think that you  know how to use useEffect, but it's really   important to understand the main concepts of this  hook. When does it run? How do dependencies work?   What's the difference between primitive and  non-primitive dependencies? When we should   use a clean-up function? I'm gonna cover all  those questions. So don't skip this video,   it's gonna be really helpful  for you to understand the basics   and you'll feel more confident when you  use useEffect in your next projects. Okay, as you can see we have a number state. In  the beginning, this number is 0. And we have a   button that increases this number using a click  event. And we show this number in this span.   I'll write here console.log, so whenever we update  our state, our component will be re-rendered.   Like that. Actually, let's write  here how many times it renders.   Okay. As you realize, at the beginning it renders  the component twice. But don't worry about that.   It's just because of React.StrictMode in the  index file. If I disable it, as you can see it   works as we expected. We are gonna talk about  this StrictMode and why it's happening soon. But before, I'll create a useEffect. And I'll  say again console.count. So we'll be able to   see when and how many times it runs. And let's  write here any effect. It can be an API request,   dom manipulation or whatever we want  to run after rendering the component.   So let's change the title of the page for  example. I'm gonna write exactly the same thing. So, when I click on this button, as you can see,  it updates the title. And as you realize there   is a really short delay between this number on  the page and this number on the title. That's   because useEffect runs after rendering the  component. It returns all these elements here,   and only after that runs this effect. Let  me demonstrate what actually happens here. Essentially we have 3 main elements.  Our component, React itself,   and the browser. And in the first render,  the number is 0. The component says: Hey,   React! You should render this HTML result. And  after rendering, don't forget to run this effect.   And React says, Hey Browser! We have some changes  to update DOM. And finally, the browser takes   those changes and shows them on the screen. And  after this rendering process, React finally runs   the effect that we give. And the browser takes  those changes and shows them on the screen again. But there is a problem here  because this useEffect runs   on every render. If I create a name state  here and update that name using this input,   whenever I write something inside this  input, my component will be re-rendered.   And as you can see the useEffect runs also. But  it's not supposed to run because it depends on   only this number. This is where we should use  useEffect dependencies. After this function,   I'll write an array and inside its dependencies.  In this case, it's gonna be this number. And it   means, run this function at the beginning, and  after, run it again when only this value changes.  And right now, as you can  see, it runs at the beginning,   it's not gonna run again even if I re-render  the component unless I change this number.   And sometimes we don't need any dependency  and we want to run an effect only once.   Let's say "Title of the app". And we don't  need this anymore, I'll delete. It'll be an   empty array. In this case, it'll run  only after the initial render. Like this. But there is something you need  to be really really careful about.   And it's the type of dependency. Let me explain. As you can see we have two states and there  is an input which updates this name state   and we show this user state here. Name is  an empty string, and selected is false.   Let's create 2 buttons. First one will be  updating the user name, and the second one will   be updating the selected boolean. Let's create  functions quickly and update object properties.   If you don't know why we are updating them like   that I highly recommend you to  watch the previous video. Okey,   as you can see it works properly.  Right now I want to create a useEffect.   And whenever we change this state, it's gonna  write "the state has changed, so useEffect runs".   Let's try. It's the initial  render. I'll update this name.   As you can see it works again because the  state has changed. I'll click here and   selected is true right now, and useEffect  runs again. Everything works perfectly.   If click again it's still true. But  as you realize useEffect runs again.   But why is that happening? Let's click here. The  name is still john, and the selected is still   true. Nothing has changed, my dependency is still  the same. Well, it's a really common problem,   and it's hard to understand for beginners because  they are struggling to understand the difference   between primitive and non-primitive data types.  But don't worry I'm gonna explain everything. Let's say there is a variable which is a string  ." john". And another one. It's "john" also.   And let's make some comparisons.  I'll say a equals b. And it's true.   They both are john. a equals john. And of course,  they are the same. Basically, john equals john. Let's do the same thing for  numbers. c equals 1, d equals 1.   And if I compare them it's gonna be  true. Is d equal to 1? Of course. And finally booleans. true equals true, false  equals false. It's exactly the same thing. So those 3 data types are primitives.  Strings, numbers and booleans are primitive. What about objects? Let's create quickly two  objects which are exactly the same. And if   I compare them, as you can see it's false. It's  happening because even if they look the same, they   refer to different points in the memory, so they  are two different objects with the same content.   You can think like two shopping carts. They  look the same, they have the same products   inside but their locations are different so  we can understand that they are two different   carts. And if I refer to exactly the same  point, these two objects will be the same.   I'm not creating a new one, I'm  just referring to the same location. Of course, I'm not gonna explain stacks,  heaps or that kind of data structure terms.   But you should know that computers compare values  of variables when they hold a string, number,   boolean, null, or undefined. But when it comes to  objects or arrays, they compare their references   instead of their content. So we can compare arrays  in the same way. And it just works like an object.   But don't misunderstand here. In React, yes we  are using dependency arrays. But React doesn't   compare two different arrays like that. It  compares every single element in this array.   Okay, if we give here variables with  primitive values. It's not a problem,   but if it's an object or array we have to be  careful. So how we can solve this issue? Actually,   there are different options. If you want to  you can create here a useMemo hook, and memoize   what you need in the state. In this case, we  are gonna need a name and selected. And this   user will be changed only if the name or selected  changes. So even if we have more properties here   it's gonna depend on only these  two. Let's change this dependency.   Okay. The name has changed but after  that, it's not gonna work again and again   because the name is still the same. Let's make  this true. And after it'll not run it again.   What else you can do?  Basically, instead of useMemo,   you can write here every single primitive  variable like that. It depends on your use case. Another mistake is to incorrectly  update the states in a useEffect.   Let's say we have a number state again. I'm gonna  write it here. What I want to do is to increase   this number every 1 second. To do that I'll use  setInterval. Every 1 second it'll update the   state like that. If you look here you'll see that  something is wrong. There is a weird glitch here.   If I write here console log.   And as you can see there is an infinite loop.  It's happening because every second the number   is changing. And since the number is  our dependency it runs this function   again and again. To solve this problem instead of  updating states using the state variable itself,   you should use an updating function. I've already  explained this function in the previous video.   And now, it runs only once  and it works almost perfectly. I say almost because it takes us to another  common problem. useEffect clean up functions.   Let's add here any text and save the file. And  as you realize it just broke the counter here.   Whenever I add something else, it gets worse.  That is because in every render we actually create   another interval without cleaning the previous  one. As you can see we have many intervals   running. Of course, to find out this issue, we  shouldn't test it by writing here something, and   this is where React Strict Mode is so important.  But we are gonna talk about it at the end of the   video. We can test it like that for now. To fix  this problem we should use a clean-up function. Let me explain how it works. It's pretty easy.  Let's say we have a toggle state and a button.   When we click on this button it updates  the toggle. If it's false it makes it true,   if it's true it makes it false again. So  basically it'll re-render the component on   every click and it's gonna trigger this useEffect.   Like that. In the first render, this effect  is gonna run anyway. But for the next renders,   we can return a clean-up function that runs  before the actual effect in order to cancel   what we did in the previous useEffect. You  are gonna understand better right now what I   mean. Let's demonstrate with console.logs. In  the initial render, it'll say useEffect runs,   and we can make something using toggle or  whatever. And when I click on this button,   before running this effect again, it's gonna  run this clean-up function so we can clean the   previous interval or event listener or whatever  we do inside this effect. I'll say "Wait!".   And after cleaning "Okey done! You can run the  effect". Okay, let's try. It's the first render.   And when I click, it runs the clean-up function  first, and only after that it runs the effect   again. And it's extremely useful. It prevents  any memory leaking and makes your applications   much faster. I'll give some use-cases and you'll  understand better. Let's get back to the previous   example. As I said we, should clean this interval.  I'll create the clean-up function. And inside   clearInterval function. Of course, we should pass  this interval in order to clear it. To do that   I'll say const interval and I'm gonna pass it  here. And let's write something. Cleaning time.   Okay. As you can see after every renders it  cleans the interval. So it doesn't occupy   a place in the memory each time. And another  most common case is fetching data from an API. Let's say we have 2 pages. This page includes  just a link. And when we click on this link   it shows the posts page and here we  are fetching data using a useEffect.   There is a fake API and it includes 100 posts.  After fetching those posts, it updates this state.   And finally, we are showing the title of  each post here. As you can see everything   looks okey. But actually, there are some  possible problems. Right now I'll go ahead   and turn on the slow mode. So we can observe  clearly. And let's write here the posts.   Okey. I'm clicking and before fetching data I want  to turn back. And as you can see even if I'm in   another component, it still fetches all these data  and updates the state. But it should be cancelled   immediately as soon as we leave the component.  This is why we need a clean-up function here. It's   a basic example, but for more complex cases with  more states, you'll have bigger problems. So you   should come here and create a clean-up. And  I'll show you a really common strategy. Firstly   I'll create here a variable. And it's gonna  be true when we fire this function. Basically,   we are gonna subscribe to this API request. And  as long as it's true, we are gonna set the state.   But when we want to cancel it's gonna be  false. This naming is not important, you can   say anything. Like isCancelled. It's easier to  understand I think. At the beginning it's gonna   be false. And in the clean-up function, it's gonna  be cancelled true. In this case, we'll update only   if it's false. Let's try. Right now, everything  works perfectly, it doesn't update the state. Let me give you one more example. We have a user  component and it fetches a single user using the   id in the URL. If it's users 1 it fetches the  first user, if it's 2 fetches the second user   so on. Finally, we have the user information  here and 3 links in order to go to different   user profiles. Basically, when we click them  the id will be changed and when the id changes   useEffect will fire this function and update the  user. So if we don't use a clean-up function,   let's see what's gonna happen. I'll turn the slow  mode on again. Now, I'll click on user2 and user3   right after that. And as you can see even if the  URL is user 3 it shows the second user first.   That is because it's not cancelling and updating  the state in any case. User1, user2, user3.   It shows us all of them and is pretty annoying.  Let's do the same thing. This time I'll use   another common naming. unsubscribed false. If  we cancel it's gonna be true. And I'll write   "cancelled". And if we are still subscribed,  which means unsubscribed is false,   we'll update the user. You can do the same  thing for the catch block also. Let's see.   Okey perfect it shows only one user. By the way, it's not the only way to cancel  requests. For beginners, it's totally okay,   but if you want to go ahead and create  a more professional clean-up function,   you can use javascript AbortController. It allows  us to intercept an API request so we can cancel it   at any time. We are gonna use its signal method  and pass it in the fetch method as an option.   Basically, when we want to cancel the request, we  are gonna send here a signal and the fetch method   will be destroyed immediately. Of course, we are  gonna send this signal in the clean-up function.   Controller and abort. Let's try. As you can see,  it throws an error. The user aborted a request.   Perfect. Let's go one step further and write here  a catch method to handle this error. I'll write a   condition. if the error name is Abort error which  identifies this error. I'll say request cancelled.   If it's something else you can write it directly  or create an error state and update it here,   whatever you want. I'll say todo: handle error.   Let's try. I'm clicking. And  perfect. It's much better right now. And if you are using Axios instead of Javascript  fetch, there is something similar. Let's change it   to axios first. It'll be a get method. I'll delete  this option we are gonna write something else.   We don't need a JSON object. It's gonna  return a response and we'll use response.data.   And I'll delete here and here. Okay. It's really  similar. We are gonna use Axios cancel token   and source. Whenever we want to cancel the request  we are gonna use the cancel method. And I'll pass   here the cancelToken like that. And finally,  Axios is gonna check whether the error comes   from the cancellation or not. If it does, it'll  write here request cancelled. Btw those codes   will be in the description below you can check  them whenever you need them. Okay. Let's try.   And Perfect. Okay, before ending let's talk about React  strict mode. I'll write here "useEffect mounts"   and "unmounts" or "useEffect runs",  "clean up runs" whatever you want.   And as you can see it runs only once. But if  I take this Strict mode back, as you can see,   this strange behaviour occurs. It just acts  like the component renders twice. But actually,   it doesn't. After React 18, it became one of  the most controversial parts of the library.   Some developers got crazy, they thought the new  version of React was broken, and they tried to   find out some strange solutions. But the answers  to all questions are already on the official   website. Firstly, there is nothing to worry about,  it happens only in development mode. So when you   deploy your apps, it's gonna work as you expected.  Secondly, it's not a bug, it just makes you sure   that there is no problem before the production.  There are some titles here that Strict mode helps.   But since this is a useEffect tutorial, I'll  explain how it affects useEffect lifecycles. For better understanding, I'm gonna open up  the previous example. I'll comment this out   again. And if you remember, even if we don't  use a clean-up function, it just works fine   and there is no way to understand  if something is wrong or not.   We just found out the problem by  adding here some additional elements.   Let's take the Strict mode back.   And right now, as you can see it  increases this number two by two.   And I understand that something is wrong. I  couldn't complete the life cycle properly.   And if I use the correct version  and clear the previous interval,   Strict mode tests it for me and it works  perfectly. Basically, This mode is really   important to find out bugs, especially in  useEffect. And I recommend you not to remove it   or try to find some weird solutions. Just leave  it like that. Believe me, it's gonna help you. Okay, I think it's enough for today.  If you learned something new today,   please like the video. And let me know which hook  you want to see in the next tutorial. Don't forget   to follow lama dev's social media accounts. I  hope I'll see you in the next tutorial. Goodbye.
Info
Channel: Lama Dev
Views: 589,123
Rating: undefined out of 5
Keywords: react, react useEffect, react useEffect hooks, useEffect, useEffect best practise, useEffect runs twice, useEffect mistakes, useEffect infinite loop, useEffect lifecycle, useEffect cleanup function, how to use useEffect, useEffect fetch, best way to fetch data with useEffect, learn react useEffect, react useEffect tutorial
Id: QQYeipc_cik
Channel Id: undefined
Length: 22min 22sec (1342 seconds)
Published: Wed Aug 10 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.