Introduction to Data Fetching in Nuxt 3
Okay then, so now I want to move on to how we can fetch external data in our next application and then use it in our components. For example, we might want to fetch data from an API and then inject that data into a component. Now the way we do that is by using a script tag, fetching the data inside that, and once we've done that, we can make it available to the template. And we're using Vue 3, so we'll make use of the Composition API and just type out setup in the script tag to do that. This is basically a bit of syntactic sugar for using the Composition API. And code inside this script is compiled as part of the normal setup function we'd use in Vue components.
So inside this script, we want to fetch the data and then make it available to the template, right? Now the way we do that in Nuxt is by using one of the built-in composable functions they provide us with for this very task. So the one we'll be using is a function called useFetch, which basically allows us to fetch data from an endpoint.
So to do this, we just type await, which we can use in this setup script at the top level, and then use the useFetch function. Now as an argument, this takes an endpoint from which we want to get data from. Now we'll get that endpoint in a minute, but before we do, I just want to explain that Nuxt can fire this code inside the script tag on both the server and in the browser. We touched on that briefly when we talked about Universal rendering at the start of the course. That's how Nuxt works. It can pre-render pages on the server by using this code inside the script tag to do things like fetch data and inject it into the template and then send that fully rendered page back to the browser. But also as well as that, once we have that page in the browser and we navigate around the site a bit, maybe to another product page, then Nuxt will fire this code in the browser to fetch any new data. So bear in mind that this code can fire on the server and in the browser. And that matters because not all code can be used on both the server and in the browser. For example, the window object is fine in the browser but will cause an error on the server. So just keep that in mind when you're working with the scripts.
Fetching a List of Products
Alright, so we want to fetch data from somewhere and we're going to use this service, fakestoreapi.com. It's basically a fake REST API that gives us a bunch of products so we can create some kind of storefront. So I'll leave this link down below the video. And if we go to read docs, we should be able to get an endpoint. And this is the endpoint that we want right here. So it's going to be fakestoreapi.com/products. And then also if we want to get a single product, you can see right here it's just forward slash and then the ID of that particular product. Okay, so these are the endpoints that we're going to be using right here.
Alright, so now inside this products index page, where we have this useFetch, I'm going to paste in that endpoint. So now this is going to fetch us all of those products, basically a list of, I think it's about 20 products, or round about that. And what we want to do is grab the data from that. So I'm going to say const and we're going to destructure something from the response. Now that something is going to be the data. So we get back a data property with all of the data. Now I don't want to call it data inside this component, I want to call it products. So we'll do that by saying colon and then say we want to call those products in this component.
So now we have this product variable and we can just use it inside our template if we want to. So let me just first of all do a little comment here to say fetch products and then spell that correctly. And then up here we want to loop through the products because this is essentially going to be an array of different objects and we want to output something for each of those products.
Displaying Products with Dynamic Links
So let's get rid of this right here and instead let's do a div. And we're going to give this a class, actually a few classes. We're using Tailwind, so let's use those Tailwind classes and we'll say grid grid-cols-4, which means there's going to be four columns going across the page, and then gap-5. So essentially we're going to output these different products in a grid on the page. Alright, so now we need to loop through the products using v-for. So let's do another div and then we'll say v-for. So loop through these, and it's going to be equal to p in products.
So I've called each individual product p but you can call it whatever you want. And this is the array that we have right here. So we're looping through those and we're outputting a div for each one of them. Now for each one of them as well, what I'd like to do is output a link to the product details page.
So I'm going to say NuxtLink like so, and then right here we'll output the title of the product. So each one of the products that we get back from the API has a title property, so we'll say p.title to access that. Alright, so now we also need a to prop and we're going to data bind to this. So colon first of all, then to and set it equal to something. And we want it to go to /products and then forward slash whatever the ID is, right? Now the ID is on this thing right here, the individual product. It's just an id property, and we want to output this in the string. So what we can do is use a template string, which is backticks right here. And then we'll say /products and then forward slash, and then to output a variable, dollar sign curly braces, and it's going to be p.id. So it's going to be /product and then forward slash the ID, whatever the ID of that particular product is. So it's going to be 1, 2, 3, 4, etc. So now on the page, we should see a grid of different product titles and each title is going to be a link. And each link is going to go to a details page of that particular product.
Verifying the Product List and Links
Now on that details page we're not outputting the product details, we're just outputting the ID of each individual product at the minute because we're grabbing that from the route. So let's save this now, cross our fingers and hope it works. So now in the browser if I click on products to go to the products page we can now see a list of titles right here. So we're successfully fetching all of that data and outputting all of the titles in a grid on this page. Now remember each one of these should be a link to the product details page for that particular item using the ID of that item. So if I click on this one we see the ID is seven up here and we get the ID 7 right here. If I click on a different one, 14, 14. So this is all working, it's going to the product details page for that particular product.
Fetching Data on the Detail Page
Now like I said before, we're not outputting any of the details for the product, just the ID that we're grabbing from the route up here. But what we could do then is use the ID to fetch that individual product from the API and then output the details of that particular product on the page.
Okay, so let's go to the details page which is this one right here. And remember, we grab the ID that's in the route so we can use that now to fetch the product which has that particular ID. So let's first of all construct the URI. So const uri is equal to, and then it's going to be the base route which is fakestoreapi.com/products and then remember it's forward slash whatever the ID is. Now that changes dependent on what the ID in the route is, so what we can do is just tack it on the end here, so + id like so. Now it's going to be /products/1 or 2 or 3, etc. So that's the endpoint we want to use.
Then we want to actually fetch the product. So let's do a comment to say that and then underneath that we'll say const and then we're going to extract the data but in this component we'll call it product singular, because we're just grabbing one product. And we set that equal to await and then useFetch, this is the composable function we're going to use just like in the products index page right here. And then we're going to pass in this URI. So let me grab that, copy and paste right here. So if we save this now we can try it out, but actually if we did that then we're not going to see anything different because we're not doing anything with this product. So let's try outputting it in the template first of all. So I'm going to do a paragraph tag for each of the attributes I want to output at the minute. The first one is going to be the product title, so double curly braces and product, which is what we called the data remember, .title. So we're using that title property on it. After that, we'll do another paragraph and out here we'll say product and then what we're going to output, the price and the ID probably. So product.price and then finally we'll output the ID, so product.id. Alright, so now let's save it and try it in the browser.
The Stale Data Problem on Dynamic Pages
Alright then, so in a browser, if we go to a product details page, we can see that this all works. We see all the data for that, it's fetching it. But there is a problem because each time we land on a details page, it's actually going to fetch the same product, right, even though we use a different ID each time from the route parameter. You can see as we go to different product details that it's all the same product.
Now, if we look under the hood, if we open up the dev tools and go to the network tab, whenever we go to a new product page, you can see no extra requests are being made to get that new product right now. This is because the useFetch function is trying to minimize the work it essentially needs to do for performance by default. And because it's been used in the same component, the product details component, even though the product ID changes, it sees no reason for it to do another fetch and it just uses the same data from the last fetch for this component, this component right here, the product details one that it made. So the way around this is to add a unique key to each fetch that we make inside the product details component.
Solution: Using a Unique Key to Force Re-fetching
So that the function has a way to differentiate between products, and that key should be something that's unique to each different product that we want to fetch. In our case, that could be the product ID because that is unique for each product. So as a second argument to the useEffect function, we could just add an options object and then inside that, we can add a key property and the value of that is just going to be id, that's the ID of the current product. And now every time we land on a new product inside this component, Nuxt sees that different key and it knows to perform a new fetch. And now in the browser, if we go to this one for example, Men's Casual Slim Fit, we get the right product. And if we go to another one now, then we get that product. So this is now working. We're getting the right product each time we click on one of these product details pages and that's because we used that key property in the options to say, hey, we need to re-fetch this data because the key is different.