تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Introducing External API0:00

Up to this point, we've been using puppies data coming from a local file. But now we're going to try to fetch this data from an external API. I've actually set up a simple Laravel API with a couple of endpoints that we can hit. This is running locally on my machine and so if we look at the /puppies endpoint, you can see it returns a puppy resource with all our puppies.

you can see it returns a Puppy resource with all our puppies. So here's the endpoint, URL, and you can see we have a data key and inside of it we have 12 puppies that are quite similar in shape to what we had locally. I said quite similar because you can see the likedBy property, which is a bit different and is a reference to a userId. So we're gonna look at how to get this data in our app, but

React Data Fetching Options0:42

which is a bit different and is a reference to a user id. So we're gonna look at how to get this data in our app, but before we do so, I need to tell you that React doesn't really provide any mechanism or API to fetch data. Matter of fact, the React docs themselves recommend using a library, something like React Query or SWR. In a real project, you're probably indeed going to use a library or framework of some sort.

In a real project, you're probably indeed going to use a library or framework of some sort. But I think it's a good exercise to see how we can go about fetching data with Vanilla React. Okay, so the puppies data from the API is slightly different from our static data we're using here. So we will temporary break things. So what I'm suggesting is before we do a refactoring to bring on the API data, we just going to try to display it somewhere here.

Creating APIPuppies Component1:23

before we do a refactoring to bring on the API data, we just going to try to display it somewhere here between the header and then the search and shortlist. So we'll keep our app as is. I will not touch any of that. But then in here before the search and short list, we'll try to add a visual output of the data that we fetch from the API. So maybe let's create a component called APIPuppies and we'll go work on that down below. So down here function APIPuppies,

and we'll go work on that down below. So down here function apiPuppies, and we'll return a div with a API. Happy placeholder, but let's add some visual separation. Uh, yeah, we can try exactly that and see what it looks like. Okay, not bad. So I'll just add some spacing at the top and reduce the padding a bit. So let's go p-6 and then mt-12. Alright, and we're going to use this box to try

Fetching with useEffect2:07

So let's go P dash six and then empty 12. Alright, and we're going to use this box to try to get our API puppies in our app. We want to fetch puppies from the API and we want to trigger a fetch request. And I'll first show you an approach that up to recently was essentially the only way to do that. So we'll use another React hook. This one is called useEffect and you can think of it as a tool when you want

This one is called useEffect and you can think of it as a tool when you want to fire a side effect, something like a fetch request. So useEffect is going to run once before the component mounts and so it's going to run the code that is inside that function and then you can determine when the effect should run again. If it needs to run again, that's a sort of funky syntax here, but it takes an array of dependencies after the function.

of funky syntax here, but it takes an array of dependencies after the function. And here you basically define when to rerun the effect. So think of it as a way to trigger a rerun of the useEffect if you need to rerun the code inside of it. So let's structure with comments what we are trying to achieve here. First, we're trying to fetch the puppies and then set them to state so we can re-render the component

First, we're trying to fetch the puppies and then set them to state so we can re-render the component and pass the state down to other components. Alright, so let's do a fetch request to our API endpoint. const response equals await fetch and the URL is http://react-backend-test/api/puppies. So here we're trying to use async await, but that only works in async functions and we can't directly set our use

but that only works in async functions and we can't directly set our useEffect function to be async. But what we can do is instead define a async function inside the useEffect and then call it. So getPuppies and let's wrap this in a try-catch so that if there's an error we can catch it and do something with it. So we're trying to get a response from the API

and do something with it. So we're trying to get a response from the API and then we can check if the response is okay and if not, throw an error. If it is okay, we can then try to get the data const data = await response.json() and for now let's console.log that data and otherwise console.log the error. So we've defined an async function here inside the useEffect and then we can call it getPuppies.

So we've defined an async function here inside the useEffect and then we can call it getPuppies. Let's remove the first comment and see what happens. So now because we have this useEffect that's going to run before the component mounts and we are using the API puppies component, now we should see in the console the result of the API call. Okay, so first let's open the network tab here and if I reload the page we should find somewhere here it is a call to the puppies react backend API endpoint.

and if I reload the page we should find somewhere here it is a call to the puppies react backend API endpoint. And you can see we have a status of 200, okay, which means that it worked properly. And if we look at the preview, we actually have this data nice. And if I look at the console, we also have data of 12 puppies. So the next step now that we want to do is set them to state so we can actually use them inside our app.

Managing Loading and Error5:02

So the next step now that we want to do is set them to state so we can actually use them inside our app. And so let's have a piece of local state called apiPuppies and setApiPuppies. Uh, the puppy type is a bit different. So for now, let's not type this as an array of puppies but just an array so it defaults to an empty array. And when we fetch the data successfully, we want to set the apiPuppies to whatever we received from the API. So here instead of console.log or

to set the apiPuppies to whatever we received from the API. So here instead of console logging or after logging the data, meh, let's replace it. We are going to set apiPuppies to the data. And because we're now bringing our data to a state, instead of logging it in the console, I'm going to do my favorite trick and have a pre tag where I JSON.stringify these apiPuppies. And so we can see our data is here already,

API puppies. And so we can see our data is here already, but if I refresh the page you can see that we start with an empty array for about one second and then when the data comes back, the data is populated in our API puppies array. And by the way, I have a little sleep function here for one second to make this a little bit more obvious since the API is running locally. Alright? And so you can imagine we need some sort

the API is running locally. Alright? And so you can imagine we need some sort of loading state while the API is loading, which is sort of like the pending state we had before. Uh, we can remove the comment here because we've done that. But up here where we have our api puppies, let's have a const isLoading and set isLoading set to not true but false. And like we've done in the previous lesson, we are going to set isLoading to true at the start.

And like we've done in the previous lesson, we are going to set isLoading to true at the start of the async function and then at the end of it we are going to set it to false and then we can use that isLoading indicator to either render the data or if it's loading we can go isLoading question. And then we can have our good old friends the Loader Circle Component with a class name of animate, spin and stroke.

component with a class name of animate, spin and stroke. What did we have? Slate 300. And otherwise we can have our pret tag. Let's try that again. Loading data. Loading data, nice. Okay, this is all good and nice and a happy path here. But let's say something went wrong with the API and it was returning a status 500 error here. So if I try to reload the page loading

and it was returning a status 500 error here. So if I try to reload the page loading and whoops, now we're showing an empty array because the loading status is back to false but we don't have any data so we didn't update our API puppies, but if we look at the network tab, I'm gonna have to reload the page. And by the way, if you wonder why the API gets hit twice here, this is something React does in development

And by the way, if you wonder why the API gets hit twice here, this is something React does in development to catch some bugs in production. It would only happen once. But here you can see we received this error message, uh, because our API call had a 500 error. The way we are currently handling this is to log an error message saying response was not okay. Remember we had it set here, but maybe here we should get the actual response knowing

Remember we had it set here, but maybe here we should get the actual response knowing that it's not okay. constant errorData equals a weightResponse that JSON and then we can throw the whole errorData. So it's going to be thrown and it's going to be caught here. And so now when we console.error that error, we are getting the whole response with the errorMessage and detail. So just like we have a loadingState,

message and detail. So just like we have a loading state, we should possibly also have an error state. And as you can see, things are getting slightly more complex as we progress. const, error, setError and instead of an error we will have a string here. And actually it can always be a string and we'll set it to an empty string. And so now just like we set the API puppies in the success

and we'll set it to an empty string. And so now just like we set the API puppies in the success path in the unsuccessful code path, let's set the error to error data, that message. And so now we have something to display. Uh, and so back in our render, if it's loading, we have a loading circle, but we sort of need to break out of this ternary to have more than one possible outcome. So we're gonna go if loading

to have more than one possible outcome. So we're gonna go if loading and end to only have one output if the status is loading and we are going to have the lotus circle in that case. And I'll remove that here if we have some data, if apiPuppies that length is greater than zero, we display that <pre> tag. And if we have an error, we are going to have yep, a red text that says the error, which is basically that. And we could even be more specific.

a red text that says the error, which is basically that. And we could even be more specific and also show the details. So in our setError here, I'll turn this into a template string so we can display more than just the message we want the message and then column and then errorData details. So let's try that. Refresh the page loading and fail to retrieve puppies. Database connection error occurred.

and fail to retrieve puppies. Database connection error occurred. As you can see, we're taking a very manual and imperative approach here. We have to keep tabs of a loading state, an error status, a data status, and then do our own little mix to make sure that we show the right thing. And that works, but it feels a bit clunky. This is precisely why the recommendation is to use some sort of library, like here, 10StackQuery.

This is precisely why the recommendation is to use some sort of library, like here, 10stack query. So if I go in the docs and go take a look at the anatomy, anatomy of a query, you can see it gives you a used query hook which is going to give access to you've guess it A is pending state is error, is success error data is fetching. And so much more, we haven't even talked about caching the data in our manual example or how to invalidate this cache.

Motivating React Query and Suspense10:41

we haven't even talked about caching the data in our manual example or how to invalidate this cache. And this is typically where something like React Query is incredibly useful. So what you're likely to use a library for that sort of stuff. I wanna show you a fairly recent addition to React, a new API, the use function, and in conjunction with something called suspense, we can make the code that we've just written

and in conjunction with something called suspense , we can make the code that we've just written before, much nicer.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟