Check out a free preview of the full Complete Intro to React, v6 course:
The "useEffect & Fetching API Data" Lesson is part of the full, Complete Intro to React, v6 course featured in this preview video. Here's what you'd learn in this lesson:

Brian live codes the useEffect hook and requestPets function to make API calls and render the Pets information received. A student's question regarding when to garbage collect is also covered in this segment.

Get Unlimited Access Now

Transcript from the "useEffect & Fetching API Data" Lesson

[00:00:00]
>> If you go back over to the course notes, we had another check point, 04-hooks. And we're gonna go on to useEffect. The number one hook that you're gonna use, by far, is useState. It's just the most useful hook that we have, every other hook is kind of derived from state in some variety.

[00:00:27] The other one that we're gonna use quite a bit, though, is one called useEffect. So, what useEffect is, is it basically allows you to have side effects to your application. So, for example, in this particular search-params, I wanna go out to my API, and I wanna fetch the list of breeds that are available per animal, right?

[00:00:48] So, if I select, let's go here to the app, dog, I wanna call the API and find out what breeds of dogs are available. And we're gonna do that through something called an effect. So, we'll just come up here and say, in addition to useState, we wanna call useEffect or import useEffect, rather.

[00:01:11] And we're also gonna import our trusty Pet component that we made earlier, Okay? We're also gonna keep track of here, a set of pets, so I'm gonna say const [pets, and setPets] = useState. This is gonna be an array of all the pets that we've gotten back from the API, cuz we're gonna program, momentarily here, all of the pets coming back from the API, okay?

[00:01:47] Underneath all these hooks, we're gonna create an effect, and we're gonna say useEffect. This is gonna be an arrow function. And this is where we're gonna put all of our async code. So, inside of here, I could directly put all of my code to request the pets. And the way you would do that, is you just use promises.

[00:02:12] But I wanna use an async function, which I think are much more pleasant to code with. So, I'm gonna create a function called requestPets. And then in here, I'm just gonna create another function called async function requestPets. Notice, I'm creating this inside of the render. The reason being is that, now I have a closure where I access breed and animal on location, right?

[00:02:41] So, I can, actually, reference the variables here, inside of the component. So, here, I'm gonna say const res, as in response, await fetch. And then, you're gonna have to type out a bit of a URL with me http://pets-v2.dev-apis.com/pets. And this is the API that I've created for you.

[00:03:21] Feel free to hammer it, it can scale quite a bit, and so. And then here, we're just gonna give it the, and notice these are backticks, as well. So, not quotes, not single quotes, but backticks, as in the one that's next to the 1 on your keyboard, that'll be important here, in just a second.

[00:03:39] So, pets?animal=${animal}. This is a template string, so, it allows me to directly input this animal here. You can do this with plus signs and string concatenation. I just like this. &location=${location}&breed=${breed}. So, this is gonna go out to our API, the pets-v2.dev-apis. Request this, And give it back to us.

[00:04:31] And we're gonna give it the animals, and the location, and breed. And it's okay if you give it empty strings, it knows what to do with that. So, yeah, now res is gonna be a response object from fetch, fetch is just a normal browser API. If you go look here, fetch, it's just built into the browser.

[00:04:59] Next thing you have to do, is you have to await, basically, the normalization of it. So, I'm gonna say const json = await res.json. And now, this JSON object, is gonna be whatever I got back from the API. So, now I can say, Yeah, let's keep going here.

[00:05:38] I'm just gonna, just to show console.log(json), so you can see what it looks like, but under that we're gonna say, setPets(json.pets). So, now, every time I call requestPets, basically, what it's gonna do, it's gonna take all this data that I have, and it's gonna go grab, whatever we were searching for from the API.

[00:05:58] We'll do the breeds stuff here in just a second. Now, we actually have a big problem here. So, actually don't, whatever. If you notice now, Probably some of you now are doing it, as well. It's making hundreds of requests to the API. So, it's actually stopped that right now.

[00:06:23] And if you come in here to useEffect and hit, [] and save again. Now, notice, we're only getting one back from the API. Between all those, you probably just made 100,000 requests to that API. [LAUGH] I mean, I certainly just made about 150 myself just by waiting. But now, notice, by putting just one set of square brackets there, we are now just making one request to that API.

[00:06:54] This square brackets is basically telling this effect, hey, when should you rerun it? It'll always run once at the beginning, right? And then, you're telling it, when do you want me to run again? If you don't give it anything, it's going to rerun after every render. Which we kind of created an infinite loop here, because every time when we call setPets, right?

[00:07:20] Every time that we update one of the hooks, or one piece of state, it's like, cool, time to rerender, right? So, we kind of hit this really gross infinite loop where you'll call setPets, which then updates it, which then says, time to call useEffect, again, right? And then, it does that again, and then it sets the pets again, and it just perpetually will make infinite requests to this, right?

[00:07:43] So, that's why we have to put these square brackets here for it to say, I want you to only do it once. Now I can say, hey, I want you to update anytime animal updates, right? So then, it's gonna check, okay, I'm only gonna update when animal changes.

[00:07:59] In fact, let's just go see what that looks like. So, if I do that, and then I choose dog, notice that it called this again. Or if I change it again to be rabbit, notice that it calls again. So, you're defining when you want that the effect to run again.

[00:08:16] Now, in reality, I actually don't want it to ever rerender unless I tell it to. So, I want it to do it once, and then I want it to just never rerender ever again, or, sorry, never call it, unless I tell it to, cuz I want it to call when I call Submit, right?

[00:08:31] I only want the user to get new search results whenever they press submit. So, let's just leave that empty, that's what that empty array means. It means, I don't want you to track anything. I only want you to render or call this effect once, and then I will call requestPets, directly, myself.

[00:08:51] Does that make sense? All right, get rid of that console.log. And now what we're gonna do, Under the form, inside the div, We're gonna say, {pets.map(pet I'm gonna use that same parentheses trick. And it's gonna be a <Pet with name={pet.name}, with a animal={pet.animal}, and breed={pet.breed}, and then we need a key, right?

[00:09:43] We talked about that, cuz we're doing a map here. So, we can just say key=. The one thing that we do know is going to be unique to each pet is that each have an ID. So, we and say pet.id, that's guaranteed unique per pet. Close it like that, and we'll end up with something like that.

[00:10:07] So, now, after we request things from the API, we'll get back a pet component for each pet that we got back from the API. So, you can see here, Notice, it's searching for, implicitly, animals from Seattle, because that's what we defined as the default state. So, we have Luna, who's my pup.

[00:10:29] Talbert, who's a cat, and Julietta who is also a dog. But now, what happens if we wanted to see animals from other places, right? So, I can just leave this empty. And this will give back all pets from all locations. Pretty cool, right? Let's address one question, or one problem that you might be seeing.

[00:10:52] If you're seeing an error about regenerator runtime, which just bites me every single time I teach about React. And, especially, when I teach, in particular, about using async await. It's from your browserslist not being correct. So, if you go back to your package.json, this browserslist needs to be something that doesn't require the regenerator runtime.

[00:11:18] So, if you have something like last 2 Chrome versions here, that should work. Make sure you're checking that's browsers, plural, list, or else it won't be right. If you do browserlist, like I constantly do, it will not work. So, browserslist. If you do that, then you need to come into here, or you can do it from here, as well.

[00:11:43] Just delete your cache, delete your dist, and then restart your server. So, I'd come in here and say delete folder, and same thing here for dist. And then, I would stop my server and restart my server, and that would probably fix it. If your stuff's working, then don't worry about it, right?

[00:12:00] That's only if stuff is broken. Okay, we do have an eslint error, as well. Let's go fix that really quick. So, here, it's saying, hey, React Hook has a missing dependency. So, one thing that this does help you with your React Hook's rules is saying, hey, if you're referencing animal in here, and you're not putting animal, so let's say that I have console.log(animal).

[00:12:32] It's gonna say, hey, you're referencing animal inside of my effect, but it's not in my dependencies, that's probably a bug. So, if I put animal in here, then it's satisfied, okay? Now what? Now, this is definitely gonna work. In fact, if we go over here again, as you may expect, empty string, but change it again, to be dog, rabbit, reptile, so on and so forth.

[00:13:01] It's just gonna help you keep those dependencies correct. In this particular case, because I never wanted to rerender, I don't wanna put anything in there. So, I just have to ignore that warning. So, the way you can do that, is you can say, eslint, -disable-line. This will just flat out disable everything about this line, which is usually not a good idea.

[00:13:28] It's usually good to say which thing you're ignoring. So I'm gonna say react-hooks/exhaustive-deps. That's the name of the rule, in particular, that we're ignoring. I don't wanna ignore all the time, but for this particular line, I wanna ignore it. And if you wanna figure out what the name of that rule is, it's just this rule right here, right?

[00:13:49] So, if you put this rule there, it'll ignore it. Okay, so that should be working. You should be getting your pets back from the API. Again, depending on what city you have there, you'll be getting different dogs back. Again, I coded this API by hand. There's only about 65 animals in there.

[00:14:16] So, if there's not an animal from your city, I'm sorry. I tried to put a decent mix of most states in there, but, yeah, that's what you got for now. The API is open source. It's on my GitHub, so, if you wanna go add more animals to it, feel free to, I will merge those pull requests.

[00:14:38]
>> I have a quick question on use hooks. I don't know if you're going to cover this later on. But I know, sometimes, with use hooks, you can get memory leaks, if you don't properly garbage collect. So, when would you do that? So, in this case would you add a garbage collecting thing for this, so it removes it, or since this is just calling it once, do we add something like that to it?

[00:14:58]
>> We're not, so, let's just do a really quick example. Sometimes, you need to clean up after yourself with effects. Actually, we can leave this, I'll have to comment on this. But let's say I had another useEffect, and by the way, you can have multiple useEffects, that's totally fine.

[00:15:15] Let's say I had one that set a timeout, and that called an alert, everyone loves alerts, right? That's high quality user experiences that we're crafting here at the moment, after 3,000 seconds, right? And this gets called every time animal changes. So, I think, if I come back here now, and I change animal, Right?

[00:15:48] It'll change it, but if I don't do anything, it's fine, that's okay. The issue now is, if I unmount animal right now, if I removed this from the DOM, it would still happen, right? Because I haven't cleaned up after myself, and this is what you're referring to. This could create memory leaks, if I have lots of this stuff happening.

[00:16:06] So, what you can actually do now, is you can actually const timer, this actually returns a number that corresponds to the timer. You can return a function here. This returned function is the cleanup function. And I can say clearTimeout(timer). And now, I'm guaranteed to clean up after myself, no matter what.

[00:16:33] Kind of advanced stuff, normally you don't have to do this. This is only really useful with timers, and subscriptions, and those kind of things. But that's what this return function does here, is, it allows you to clean up after yourself after you're done. This return function is a cleanup function, it only gets called when your component is removed.

[00:16:51] So, if I went from search-params to a different page, it would remove all that stuff from the DOM, and so it would call all those cleanup functions, okay? So, let's delete all this stuff. There is a checkpoint now. So, if you go to 05 useEffect, that's the state of the repo at the moment, and we should be good to go.