Client-Side GraphQL in React

Querying Mutations Solution

Scott Moss

Scott Moss

Superfilter AI
Client-Side GraphQL in React

Check out a free preview of the full Client-Side GraphQL in React course

The "Querying Mutations Solution" Lesson is part of the full, Client-Side GraphQL in React course featured in this preview video. Here's what you'd learn in this lesson:

Scott live codes the solution to the querying mutations exercise.


Transcript from the "Querying Mutations Solution" Lesson

>> Scott Moss: I had already created my mutation in the graphical Apollo tools that we have here in the Dev tool section. And for me, it's mostly exactly what I want to use in React, so I'm just gonna copy that and I'm gonna head over to our React code. First thing is I need to make a query for that mutation, so I'm going to const.

And I'm gonna call this one a NEW_PET, like that. I'm gonna use the gql tag here. And I'm just going to paste that mutation in there and fix this indentation. There we go. So now we got a mutation and just to recap this, so we have the mutation keyword which telegraph kill that we're running a mutation type of operation here.

And then you have the operation name, which is gonna be, in my case it's CreateAPet. You could name this whatever you want. I'm declaring a variable here by the name of newPet and setting its type to a new input, which is non-null so it's required when writing this operation.

And then I'm going to run the addPet mutation and I'm going to satisfy its input argument and set that to the newPet variable that I created above in the CreateAPet operation. And then I'm gonna ask for these fields. And as far as the fields go, I selected the fields id, name, type, and image because they're the exact same fields that I have for ALL_PETS.

Because what I wanna do is I wanna be able to create a pet and have it show up in the list of Pets. And to make sure nothing goes wrong, if no components error out, I should pass in the exact same fields that the ALL_PETS query does. Otherwise, like I said, you could get an error if your components are expecting something, you would just have to do a refetch.

You'd have to refetch the query if you needed some additional information. So you don't wanna have to do a refetch when the mutation can just return exactly what you need, so you might also just ask for the same fields. So I'm asking for the same fields there. The next thing is I can use the useMutation hook applied to us by @apollo/react-hooks useMutation.

And for this I'm just going to pass in the mutation that we created above, which is called NEW_PET. So I'll say NEW_PET, like that. And then you're gonna get back an array. The first thing is gonna be the actual mutation function that you can use to call the mutation.

So again, unlike useQuery, useMutation doesn't execute. It makes a network call when you instantiate it like this. It doesn't make the call, and so you call the function provided to you from the hook. And then you get back this object that's very similar to the object you get when you use a query.

So it's gonna have a data, loading, error, and other things that you might find necessary. So I'm just going to name space mine as newPet.
>> Scott Moss: So now that I have that, I'm gonna go to this onSubmit function, which if you looked a little further, this onSubmit function is tied to this NewPetModal that has onSubmit, and you're just passing to that.

That NewPetModal encapsulates that logic for you, so you don't have to worry about it. And it's hidden behind an if (modal) flag. That flag is toggle to Boolean when you click on the Create a new pet button. So you don't have to worry about all that, ti's just set up context.

So inside his onSubmit function, I wanna call a createPet. And any mutation function is going to take an object of properties and you can look at the Apollo client docs for this. But the one that we're interested in, in this case is called variables. And variables are gonna be the exact same variables as we have down here in graphical, which are called Query Variables.

So we want to pass an object that looks exactly like this. It has a newPet because that's the name of the variable that we declared in our mutation. Your variable name might be different. So whatever you named your variable up here with the $, that's the name of the variable that you're going to pass to the variables object here.

And any other variables that you might have passed. If for whatever reason you had other variables here like that, then you would place that as a key down here as well. Minus the dollar sign. You dont do dollar other. So if you did that then that's were these go.

So theres viable go there. So for use we have a newPet variable and its type is a NewPetInput. So I'm gonna say a newPet variable and its type needs to be NewPetInput. If you go to look at a NewPetInput it has a object with a name and a type.

A name is a String and a type is a PetTyp, which is a enum which is a string. So it's gotta be CAT or a DOG. Luckily for you, this input that comes in on onSubmit is already formatted that way. It is an object with a name and a type that's guaranteed to be one of those enums.

So you don't have to think about it. So you need just set newPet: input. And you should be good to go. So now we have that there. And the next thing we need to do is account for when we're loading and if we have an error and things like that.

So I'll say if loading or if newPet.loading. And then I'll say if error or if newPet.error. That's it. So now we're handling the error and we're handling the loading state. We should be able to go and create a pet. So let's try that. So right now I have these four pets.

[INAUDIBLE] Make a new Cat call it Garfield. I can add that cat. It doesn't show up on the list, but if you refresh it we should see Garfield there.
>> Scott Moss: All right, did everyone get to this part? Were they able to create a pet and get it going, right?

Pretty simple, right? I mean, I think it's pretty intuitive of how Apollo set that up. Trust me, this is at least for me the third approach for using Apollo and React. And so far this is the easiest approach that I've seen. Before this, before hooks and stuff basically you have to compose the components using like higher order components, which in my opinion, using React I'm not a fan of higher order components.

I think it gets really sloppy, and I think that's another reason why they came up with hooks. Higher order components, wrapping other components, wrapping other components, wrapping other components forever and ever and ever. To me that can get really sloppy and for a lot of people it's very confusing to look at, follow that all the way down.

So that was the other approach. This one to me just makes way more sense. Well, also in my opinion, I find that even though this is simple and is really intuitive, using Apollo in other frameworks is even easier. In Angular and Vue, for me Apollo is a lot easier to use even in React at this point, even though this is simple.

So just imagine how simple those frameworks are to use. So you get pretty good results here. And another thing to note is we don't have to wait on this. Just like we didn't have to wait on this use query, and that's because this is a hook. When we create a pet, and that comes back from the server in the background, and it updates the data property in this newPet object, this is gonna rerender.

And that's why we have a loading state, and that's how we have an error state because we're not, waiting for this to be resolved. We don't have to wait at all. When the data get set, that's gonna trigger, rerender, and react. That's the whole point it reacts, when the state changes, when props changes, the whole components gonna react.

So, we don't have to worry about waiting for it. We just let React do its job, and we get a new render whenever any property changes here. So there's no waiting for any of that stuff. If you want to wait for something, then, yeah, you could totally do that, you just wouldn't use a hook.

You would use the client directly, just like we did earlier today where we had something like client.query. You would do something like that. And this returns a promise, so you could wait that if you wanted to. And that's something where you would want to wait and do things like that.

But the hooks are meant just for retrieving data inside a component life cycle. And that's the whole purpose. But again, if you were retrieving data outside of a component life cycle you probably wouldn't use hooks and you would just use a client directly and do a .query or a .mutation because you're not even inside of React.

So you're probably not even using React. Maybe you're using jQuery or something like that. So you would just use it directly. So why didn't our panelists update? Or who expected our pitless to update automatically? Okay, one person. So everybody, I think it's cuz I told you I wasn't gonna update, it's stupid question.

Who here knows why I didn't update? Tiff?
>> Tiff: We need to be able to refresh the view when there is an update to the data, like it needs to be tied to some sort of state. React right now doesn't know that the data has changed, so.
>> Scott Moss: Yeah, React doesn't know that the data's changed because there's this and we're not even using that anywhere.

I mean, I guess I could, I don't know, take and append it to data.pets, just stick it in there. What you would normally do here is you say, cool. I have a data structure, I have a collection of pets. That's an array of pets. I added a new one on the server.

It came back. I'm just gonna push into this pets array. If you're using Redux you would reduce over this and create a whole new immutable array. Spread the previous results, add the new one to the front, and then you're done. That's what Redux does. That's what pretty much an immutable state machine is gonna do.

And that's probably what your first reaction what to do here, is like, okay, if you take the data.pets make a clone of it, make a new array, add the one that I just got back from newPets. And then instead of passing data.pets to pets down here, I'll pass my new array and then everything just works.

Yeah, that would work, 100% that would that would work. But there is a better way to do it. Because if you do it that way, sure you updated your components that have the right state. And it wold work but your doing all this cloning of immutable data and stuff like that.

But your cache, your Apollo cache wouldn't have the right data in it. Your cache would still not have that newPet that you created. So anything else in your app that's relying on this query and that cache is also not gonna have it. So only this component would be up to date and no other component.

And you're kinda defeating the purpose of using a cache. You're getting to the point where, I mean you're only one step away from just storing stuff in a dom at that point. You must so just go further and do that. So you don't wanna do that. Instead, we wanna update the cache.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now