Introduction: Fetching Reviews by Category
Alright and gang, so we talked a little bit in the last lesson about relational data. And we created a second data collection type called categories and we related that to the reviews, right? And then what we did in our application is grab those categories inside the header, the site header right here, and we just listed them out. So if we click on one of those, it goes to the category page where the ID of the category is in the route. Now what I'd like to do in this page is then show the reviews that are related to that category. So this is going to mean that first of all, we're going to fetch that category with that ID from Strapi, and once we have that category, we can say look, fetch me all the reviews related to that category. So if I choose the PS5 for example, then it should just fetch me, if we go to reviews, BioMutant and Rocket League. Okay, so let's give that a whirl.
Building a Nested GraphQL Query
What I'm gonna do is come to our category page. First of all, let me get rid of some of these, we don't need these anymore, and open up the category page. So first of all, I'm gonna import a couple of things from Apollo Client: useQuery and gql. They're the two things we always import when we're using GraphQL in a component.
So next let's make the query. So I'm gonna say const, and we'll call this CATEGORY because we just want a single category. And we set this equal to gql and then template strings, and inside here we make the query. So, query, and then we'll call this GetCategory. Now again, we're going to use some kind of query variable in here. So let's do parentheses and we're going to take in an ID, and we'll call this ID like so, and it's going to be of type ID with an exclamation mark on to say it can't be null.
Okay, so inside here we want a single category. So category, and we want the category with this ID that we're going to pass in. So we'll say in here the ID must match the ID variable. Okay, so for the category, I want the name because we're going to list that category title up at the top of the page up here. I also want the ID, and also I want all the reviews related to that. Now remember when we said there was a relation between categories and reviews, it added properties, extra properties to the category which was called reviews, and it added an extra property to reviews which was called category. So what I can do is say, look, we've got the category, now get me all the reviews that you're related to.
And it does that, but I need to say inside curly braces what properties I want from the reviews as well. So for example, I could want the title, also the body, also the rating, also the ID, like so. And what's more, I could then say look for these reviews, I also want the categories they're associated with. Now you might be scratching your head thinking what's the point in that? Because we already got the category that this review is in. But remember, a review can be in more than one category. So we might be on the PS5 category page for example and know that category, but the review might also be in the Xbox category. So I want to list each of these categories that this review is in as well. And that is going to go, if we take a look at the homepage, you see we have the console list. It's going to go in that part of the template later on.
All right, so now we're saying okay, get in the category, the name and the ID from that. Also get me the reviews and these properties from the reviews, and get me the categories in that review. So from that we want the name and the ID. And this is pretty good, right? We're doing this all in one query.
Executing the Query in React
So now what we need to do is use that query using the useQuery hook. Now, first of all we need to grab the ID from the route and to do that we need to the useParams hook. So let me just import a couple of things at the top. I'm going to import useParams and also Link because we're going to use that in the template from react-router-dom.
Now next up, we'll use the useParams hook to grab the ID here. And then next we'll use the useQuery hook to send this query right here called CATEGORY. So let me paste this in. So we grab these three things: loading, error, and data from useQuery. We're passing CATEGORY, which is the name of this query, and then we pass in the variables right here. The only one we pass in is the id, which is the one we get from useParams in the route. So we pass that in, it grabs the category, the reviews associated with it, and for each of those reviews, the categories as well. Cool.
So now we can return those conditional templates if it's loading or if there's an error. And also, I'm going to log out the data we get back just in case we want to look at it inside the console.
Alright, so then we just need some kind of template. Now this is going to be pretty much the same as the home page where we cycle through the reviews. So let me grab this where we map through them. I'm going to copy that and I'm going to come over here and I'm going to paste it inside this div. So let me do that, but before that, I want to output the title of the category. So I'll do an H2 for that and I'll say data.category.name. Remember we get that property from the category. Okay, so we output the title first of all.
Then we say data.reviews. Now that's not going to work, because it should be category.reviews because the reviews are embedded in the category. So we need to say data.category first of all, then .reviews, cycle through them, and for each review right here we output a div. We use the review ID. We have a class of review-card and then we output the rating and the title. The console list is going to go here in a second. And then we output a substring of the body and also we link to the details of that review. So let me save this and preview so far, and we can see this works. So this is the PS5 category, and it gets me the items in the PS5 category. If I go to Switch, I get these ones. If I go to Xbox, these ones. So this all works now. And if I click on one of these read mores, it works.
Displaying Nested Category Data on Review Cards
So now I want to output the console list which is going to go right here. So remember for each review, we got the categories, so all we're going to do is cycle through the categories. So let me do that. I'm going to come here and say review.categories, because the review is what we have right here, and then we have a categories property on that, and we're going to map through the categories. So let me say .map and then I'll refer to each category as c, and then inside here we're going to return a simple template which is just going to be this small tag for each category. Let me paste that in right here. And instead of outputting console list, all we need to do is output c.name, the name property on the category which we get. And also we need to add a key to this, which is going to be equal to c.id, so the ID of the category, which we get as well.
So if I save this now and a preview, we can see these categories under each one of these reviews. So if I go to PS5, each one of these should have PS5 below it. If I go to Switch, they should all have Switch below it, which they do. And this one, Xbox, Xbox, and Xbox. Awesome, cool.
Updating Other Pages with Relational Data
So that's how we grab relational data or related data by just embedding it inside the same query, which is really, really good. Now I want to do a similar thing as this right here on the home page. So let me go to the home page and I'll put it right here. But in order to do this, we need to get the categories from the review. So right here, we'll say categories as well we want. And inside that we want the name and the ID. So if I save this, hopefully, fingers crossed, if I go to the home page, now we get the categories.
And I'll do the same thing for the review details. So let's go over here and inside the review, we'll get the categories like so. And inside that we want the ID and the name. And down here we can output the template for that like so. Save it, and okay, that doesn't work. Because review is not defined. It should be, for the review details, data.review, because we're not cycling through anything. We just get the review directly from the data object. So we'll say data.review.categories and hopefully this should work. Awesome!
Alright then my friends, so that's pretty much all done. There is one more thing I want to do and that is to talk about the rich content editor inside Strapi right here. We can make things bold and whatnot but you do have to do one extra thing when it comes to working with rich text in React, and we'll see how to do that next.