All useEffect Mistakes Every Junior React Developer Makes

All useEffect Mistakes Every Junior React Developer Makes


All useEffect Mistakes Every Junior React Developer Makes

Learn React useEffect hook from scratch. React useEffect tutorial beginner to advanced. useEffect best practices. Clean up, lifecycle, and rendering problems.

For more projects you can support Lama Dev:

Join:    / @lamadev  
Buy me a coffee: https://www.buymeacoffee.com/lamadev

Join Lama Dev groups
Facebook: https://www.facebook.com/groups/lamadev
Instagram: https://www.instagram.com/lamawebdev
Discord: https://discord.gg/yKremu4mPr
Twitter: https://twitter.com/lamawebdev

Source Code: https://github.com/safak/youtube2022/

0:00 Understanding useEffect
04:10 useEffect Dependency Mistakes
09:39 useEffect Updating State Correctly
10:58 useEffect Clean-up Functions Explained
13:50 Best Ways to Make API Requests with useEffect


Content

0.24 -> Hello friends, let’s try to understand useEffect  and how it works, and talk about the most common  
6.48 -> useEffect problems. You might think that you  know how to use useEffect, but it's really  
12 -> important to understand the main concepts of this  hook. When does it run? How do dependencies work?  
18 -> What's the difference between primitive and  non-primitive dependencies? When we should  
23.12 -> use a clean-up function? I'm gonna cover all  those questions. So don't skip this video,  
29.2 -> it's gonna be really helpful  for you to understand the basics  
32.48 -> and you'll feel more confident when you  use useEffect in your next projects.
37.92 -> Okay, as you can see we have a number state. In  the beginning, this number is 0. And we have a  
44.56 -> button that increases this number using a click  event. And we show this number in this span.  
51.28 -> I'll write here console.log, so whenever we update  our state, our component will be re-rendered.  
59.52 -> Like that. Actually, let's write  here how many times it renders.  
66.08 -> Okay. As you realize, at the beginning it renders  the component twice. But don't worry about that.  
72.48 -> It's just because of React.StrictMode in the  index file. If I disable it, as you can see it  
79.44 -> works as we expected. We are gonna talk about  this StrictMode and why it's happening soon.
85.36 -> But before, I'll create a useEffect. And I'll  say again console.count. So we'll be able to  
92.08 -> see when and how many times it runs. And let's  write here any effect. It can be an API request,  
100.08 -> dom manipulation or whatever we want  to run after rendering the component.  
104.96 -> So let's change the title of the page for  example. I'm gonna write exactly the same thing.
112.32 -> So, when I click on this button, as you can see,  it updates the title. And as you realize there  
118.56 -> is a really short delay between this number on  the page and this number on the title. That's  
123.84 -> because useEffect runs after rendering the  component. It returns all these elements here,  
129.44 -> and only after that runs this effect. Let  me demonstrate what actually happens here.
135.76 -> Essentially we have 3 main elements.  Our component, React itself,  
141.12 -> and the browser. And in the first render,  the number is 0. The component says: Hey,  
147.12 -> React! You should render this HTML result. And  after rendering, don't forget to run this effect.  
153.84 -> And React says, Hey Browser! We have some changes  to update DOM. And finally, the browser takes  
160.16 -> those changes and shows them on the screen. And  after this rendering process, React finally runs  
167.04 -> the effect that we give. And the browser takes  those changes and shows them on the screen again.
173.28 -> But there is a problem here  because this useEffect runs  
176.56 -> on every render. If I create a name state  here and update that name using this input,  
186.64 -> whenever I write something inside this  input, my component will be re-rendered.  
192.48 -> And as you can see the useEffect runs also. But  it's not supposed to run because it depends on  
198.8 -> only this number. This is where we should use  useEffect dependencies. After this function,  
205.28 -> I'll write an array and inside its dependencies.  In this case, it's gonna be this number. And it  
212.32 -> means, run this function at the beginning, and  after, run it again when only this value changes. 
219.12 -> And right now, as you can  see, it runs at the beginning,  
222.16 -> it's not gonna run again even if I re-render  the component unless I change this number.  
230.88 -> And sometimes we don't need any dependency  and we want to run an effect only once.  
236.8 -> Let's say "Title of the app". And we don't  need this anymore, I'll delete. It'll be an  
242.32 -> empty array. In this case, it'll run  only after the initial render. Like this.
250.08 -> But there is something you need  to be really really careful about.  
254.56 -> And it's the type of dependency. Let me explain.
258.96 -> As you can see we have two states and there  is an input which updates this name state  
264.96 -> and we show this user state here. Name is  an empty string, and selected is false.  
271.68 -> Let's create 2 buttons. First one will be  updating the user name, and the second one will  
277.44 -> be updating the selected boolean. Let's create  functions quickly and update object properties.  
289.84 -> If you don't know why we are updating them like  
292.08 -> that I highly recommend you to  watch the previous video. Okey,  
306.8 -> as you can see it works properly.  Right now I want to create a useEffect.  
313.84 -> And whenever we change this state, it's gonna  write "the state has changed, so useEffect runs".  
321.84 -> Let's try. It's the initial  render. I'll update this name.  
328.24 -> As you can see it works again because the  state has changed. I'll click here and  
333.92 -> selected is true right now, and useEffect  runs again. Everything works perfectly.  
340.08 -> If click again it's still true. But  as you realize useEffect runs again.  
346.88 -> But why is that happening? Let's click here. The  name is still john, and the selected is still  
353.52 -> true. Nothing has changed, my dependency is still  the same. Well, it's a really common problem,  
360.48 -> and it's hard to understand for beginners because  they are struggling to understand the difference  
365.44 -> between primitive and non-primitive data types.  But don't worry I'm gonna explain everything.
372.72 -> Let's say there is a variable which is a string  ." john". And another one. It's "john" also.  
380.08 -> And let's make some comparisons.  I'll say a equals b. And it's true.  
387.28 -> They both are john. a equals john. And of course,  they are the same. Basically, john equals john.
396.24 -> Let's do the same thing for  numbers. c equals 1, d equals 1.  
402.4 -> And if I compare them it's gonna be  true. Is d equal to 1? Of course.
408.96 -> And finally booleans. true equals true, false  equals false. It's exactly the same thing.
417.68 -> So those 3 data types are primitives.  Strings, numbers and booleans are primitive.
425.76 -> What about objects? Let's create quickly two  objects which are exactly the same. And if  
432 -> I compare them, as you can see it's false. It's  happening because even if they look the same, they  
439.36 -> refer to different points in the memory, so they  are two different objects with the same content.  
445.76 -> You can think like two shopping carts. They  look the same, they have the same products  
450.8 -> inside but their locations are different so  we can understand that they are two different  
456.32 -> carts. And if I refer to exactly the same  point, these two objects will be the same.  
462.96 -> I'm not creating a new one, I'm  just referring to the same location.
467.84 -> Of course, I'm not gonna explain stacks,  heaps or that kind of data structure terms.  
473.04 -> But you should know that computers compare values  of variables when they hold a string, number,  
479.76 -> boolean, null, or undefined. But when it comes to  objects or arrays, they compare their references  
487.28 -> instead of their content. So we can compare arrays  in the same way. And it just works like an object.  
496.72 -> But don't misunderstand here. In React, yes we  are using dependency arrays. But React doesn't  
503.2 -> compare two different arrays like that. It  compares every single element in this array.  
511.04 -> Okay, if we give here variables with  primitive values. It's not a problem,  
515.44 -> but if it's an object or array we have to be  careful. So how we can solve this issue? Actually,  
522.64 -> there are different options. If you want to  you can create here a useMemo hook, and memoize  
528.64 -> what you need in the state. In this case, we  are gonna need a name and selected. And this  
534.4 -> user will be changed only if the name or selected  changes. So even if we have more properties here  
543.36 -> it's gonna depend on only these  two. Let's change this dependency.  
551.52 -> Okay. The name has changed but after  that, it's not gonna work again and again  
558.8 -> because the name is still the same. Let's make  this true. And after it'll not run it again.  
565.6 -> What else you can do?  Basically, instead of useMemo,  
569.6 -> you can write here every single primitive  variable like that. It depends on your use case.
579.2 -> Another mistake is to incorrectly  update the states in a useEffect.  
584.48 -> Let's say we have a number state again. I'm gonna  write it here. What I want to do is to increase  
593.04 -> this number every 1 second. To do that I'll use  setInterval. Every 1 second it'll update the  
601.52 -> state like that. If you look here you'll see that  something is wrong. There is a weird glitch here.  
616.4 -> If I write here console log.  
622.48 -> And as you can see there is an infinite loop.  It's happening because every second the number  
628.56 -> is changing. And since the number is  our dependency it runs this function  
634 -> again and again. To solve this problem instead of  updating states using the state variable itself,  
640.48 -> you should use an updating function. I've already  explained this function in the previous video.  
646.64 -> And now, it runs only once  and it works almost perfectly.
653.04 -> I say almost because it takes us to another  common problem. useEffect clean up functions.  
661.12 -> Let's add here any text and save the file. And  as you realize it just broke the counter here.  
668.72 -> Whenever I add something else, it gets worse.  That is because in every render we actually create  
677.04 -> another interval without cleaning the previous  one. As you can see we have many intervals  
682.32 -> running. Of course, to find out this issue, we  shouldn't test it by writing here something, and  
687.92 -> this is where React Strict Mode is so important.  But we are gonna talk about it at the end of the  
693.92 -> video. We can test it like that for now. To fix  this problem we should use a clean-up function.
700.16 -> Let me explain how it works. It's pretty easy.  Let's say we have a toggle state and a button.  
706.32 -> When we click on this button it updates  the toggle. If it's false it makes it true,  
711.44 -> if it's true it makes it false again. So  basically it'll re-render the component on  
716.56 -> every click and it's gonna trigger this useEffect.  
720.32 -> Like that. In the first render, this effect  is gonna run anyway. But for the next renders,  
726.4 -> we can return a clean-up function that runs  before the actual effect in order to cancel  
732.4 -> what we did in the previous useEffect. You  are gonna understand better right now what I  
736.56 -> mean. Let's demonstrate with console.logs. In  the initial render, it'll say useEffect runs,  
742.88 -> and we can make something using toggle or  whatever. And when I click on this button,  
748.32 -> before running this effect again, it's gonna  run this clean-up function so we can clean the  
754.48 -> previous interval or event listener or whatever  we do inside this effect. I'll say "Wait!".  
765.36 -> And after cleaning "Okey done! You can run the  effect". Okay, let's try. It's the first render.  
774 -> And when I click, it runs the clean-up function  first, and only after that it runs the effect  
780 -> again. And it's extremely useful. It prevents  any memory leaking and makes your applications  
786.88 -> much faster. I'll give some use-cases and you'll  understand better. Let's get back to the previous  
792.8 -> example. As I said we, should clean this interval.  I'll create the clean-up function. And inside  
799.44 -> clearInterval function. Of course, we should pass  this interval in order to clear it. To do that  
805.6 -> I'll say const interval and I'm gonna pass it  here. And let's write something. Cleaning time.  
816.88 -> Okay. As you can see after every renders it  cleans the interval. So it doesn't occupy  
822.96 -> a place in the memory each time. And another  most common case is fetching data from an API.
830.88 -> Let's say we have 2 pages. This page includes  just a link. And when we click on this link  
837.52 -> it shows the posts page and here we  are fetching data using a useEffect.  
844.08 -> There is a fake API and it includes 100 posts.  After fetching those posts, it updates this state.  
852.96 -> And finally, we are showing the title of  each post here. As you can see everything  
857.92 -> looks okey. But actually, there are some  possible problems. Right now I'll go ahead  
864 -> and turn on the slow mode. So we can observe  clearly. And let's write here the posts.  
872.4 -> Okey. I'm clicking and before fetching data I want  to turn back. And as you can see even if I'm in  
879.92 -> another component, it still fetches all these data  and updates the state. But it should be cancelled  
887.12 -> immediately as soon as we leave the component.  This is why we need a clean-up function here. It's  
893.36 -> a basic example, but for more complex cases with  more states, you'll have bigger problems. So you  
899.36 -> should come here and create a clean-up. And  I'll show you a really common strategy. Firstly  
906 -> I'll create here a variable. And it's gonna  be true when we fire this function. Basically,  
911.12 -> we are gonna subscribe to this API request. And  as long as it's true, we are gonna set the state.  
918.08 -> But when we want to cancel it's gonna be  false. This naming is not important, you can  
923.76 -> say anything. Like isCancelled. It's easier to  understand I think. At the beginning it's gonna  
928.88 -> be false. And in the clean-up function, it's gonna  be cancelled true. In this case, we'll update only  
936.24 -> if it's false. Let's try. Right now, everything  works perfectly, it doesn't update the state.
945.12 -> Let me give you one more example. We have a user  component and it fetches a single user using the  
951.44 -> id in the URL. If it's users 1 it fetches the  first user, if it's 2 fetches the second user  
958.56 -> so on. Finally, we have the user information  here and 3 links in order to go to different  
964.72 -> user profiles. Basically, when we click them  the id will be changed and when the id changes  
970.88 -> useEffect will fire this function and update the  user. So if we don't use a clean-up function,  
977.2 -> let's see what's gonna happen. I'll turn the slow  mode on again. Now, I'll click on user2 and user3  
984.72 -> right after that. And as you can see even if the  URL is user 3 it shows the second user first.  
991.44 -> That is because it's not cancelling and updating  the state in any case. User1, user2, user3.  
999.92 -> It shows us all of them and is pretty annoying.  Let's do the same thing. This time I'll use  
1007.36 -> another common naming. unsubscribed false. If  we cancel it's gonna be true. And I'll write  
1015.52 -> "cancelled". And if we are still subscribed,  which means unsubscribed is false,  
1021.36 -> we'll update the user. You can do the same  thing for the catch block also. Let's see.  
1028.8 -> Okey perfect it shows only one user.
1032.16 -> By the way, it's not the only way to cancel  requests. For beginners, it's totally okay,  
1038 -> but if you want to go ahead and create  a more professional clean-up function,  
1042.32 -> you can use javascript AbortController. It allows  us to intercept an API request so we can cancel it  
1049.84 -> at any time. We are gonna use its signal method  and pass it in the fetch method as an option.  
1056.4 -> Basically, when we want to cancel the request, we  are gonna send here a signal and the fetch method  
1061.84 -> will be destroyed immediately. Of course, we are  gonna send this signal in the clean-up function.  
1067.6 -> Controller and abort. Let's try. As you can see,  it throws an error. The user aborted a request.  
1078 -> Perfect. Let's go one step further and write here  a catch method to handle this error. I'll write a  
1084.56 -> condition. if the error name is Abort error which  identifies this error. I'll say request cancelled.  
1093.28 -> If it's something else you can write it directly  or create an error state and update it here,  
1099.84 -> whatever you want. I'll say todo: handle error.  
1103.84 -> Let's try. I'm clicking. And  perfect. It's much better right now.
1110.64 -> And if you are using Axios instead of Javascript  fetch, there is something similar. Let's change it  
1116.08 -> to axios first. It'll be a get method. I'll delete  this option we are gonna write something else.  
1122.24 -> We don't need a JSON object. It's gonna  return a response and we'll use response.data.  
1129.12 -> And I'll delete here and here. Okay. It's really  similar. We are gonna use Axios cancel token  
1139.12 -> and source. Whenever we want to cancel the request  we are gonna use the cancel method. And I'll pass  
1146.4 -> here the cancelToken like that. And finally,  Axios is gonna check whether the error comes  
1153.92 -> from the cancellation or not. If it does, it'll  write here request cancelled. Btw those codes  
1161.04 -> will be in the description below you can check  them whenever you need them. Okay. Let's try.  
1171.36 -> And Perfect.
1176.96 -> Okay, before ending let's talk about React  strict mode. I'll write here "useEffect mounts"  
1188.16 -> and "unmounts" or "useEffect runs",  "clean up runs" whatever you want.  
1198.96 -> And as you can see it runs only once. But if  I take this Strict mode back, as you can see,  
1205.6 -> this strange behaviour occurs. It just acts  like the component renders twice. But actually,  
1211.68 -> it doesn't. After React 18, it became one of  the most controversial parts of the library.  
1217.04 -> Some developers got crazy, they thought the new  version of React was broken, and they tried to  
1222.96 -> find out some strange solutions. But the answers  to all questions are already on the official  
1228.88 -> website. Firstly, there is nothing to worry about,  it happens only in development mode. So when you  
1235.28 -> deploy your apps, it's gonna work as you expected.  Secondly, it's not a bug, it just makes you sure  
1241.68 -> that there is no problem before the production.  There are some titles here that Strict mode helps.  
1247.36 -> But since this is a useEffect tutorial, I'll  explain how it affects useEffect lifecycles.
1254.16 -> For better understanding, I'm gonna open up  the previous example. I'll comment this out  
1260.24 -> again. And if you remember, even if we don't  use a clean-up function, it just works fine  
1268.08 -> and there is no way to understand  if something is wrong or not.  
1274.32 -> We just found out the problem by  adding here some additional elements.  
1280.32 -> Let's take the Strict mode back.  
1287.12 -> And right now, as you can see it  increases this number two by two.  
1292.08 -> And I understand that something is wrong. I  couldn't complete the life cycle properly.  
1301.44 -> And if I use the correct version  and clear the previous interval,  
1306.64 -> Strict mode tests it for me and it works  perfectly. Basically, This mode is really  
1313.04 -> important to find out bugs, especially in  useEffect. And I recommend you not to remove it  
1319.76 -> or try to find some weird solutions. Just leave  it like that. Believe me, it's gonna help you.
1325.84 -> Okay, I think it's enough for today.  If you learned something new today,  
1330 -> please like the video. And let me know which hook  you want to see in the next tutorial. Don't forget  
1335.84 -> to follow lama dev's social media accounts. I  hope I'll see you in the next tutorial. Goodbye.

Source: https://www.youtube.com/watch?v=QQYeipc_cik