Optimistic updates are great for user experience. In this lesson we purposefully setup the remove dogs handler to wait several seconds to return. That meant for an awkward experience for users while waiting for the dog deletion to go through. It's going to go through 99% of the time right? Why not just respond like it worked? That's what optimistic updates allow you to do.
In every query or mutation you define, you have the option of including an onQueryStarted
listener, which will be executed just as the query is fired off. In there you receive the arguments passed into the query or mutation as the first, and then a number of utilities including dispatch
passed as the second argument.
This will let you dispatch(api.util.updateQueryData(<queryName>, <queryArgument>, <modificationFn>))
and modify the cached data stored for that particular query.
If you're using invalidateTags
with your mutation as well as manually modifying the cache, your cache will be updated immediately and then refetched after the mutation was successful.
Two example of optimistic updates with RTK Query can be found here:
Man 1: [0:00] In apiSlice.js, let's go ahead and add a new mutation called removeDog. For the query, we're going to take in an ID. That's going to return an object where the url is /dogs/id and the method is going to be delete.
[0:12] Also, we want to make sure that we tell it to invalidate the tag for dogs. Now, we can export the useRemoveDogMutation and let's go ahead and import that inside our DogsPage. We'll say const removeDog equals useRemoveDogMutation. We can get rid of the old removeDog imported from our dog slice.
[0:32] Instead of dispatching removeDog, we'll just call our new removeDog method directly and we'll get rid of our dispatch as well. When I go into the DogsPage, and I click to remove a dog, you'll notice it takes quite some time before it's actually removed. That's because in our route handler actually have it hard coded to take around two and a half seconds to process that delete.
[0:52] That makes us a perfect use case to try out optimistic updates. Back in apiSlice.js, we need a new property called onQueryStarted. That's first going to take the ID and then an object, which has one of its properties as dispatch. Inside of that method, we're going to type dispatch(api.util.updateQueryData).
[1:15] Now, we need to tell it the query that we want to modify. When we remove a dog, we actually want to change the results of the getDogsQuery. We'll say getDogs. The next argument is whatever argument you'd pass into the getDogs, which in this case is actually undefined. We don't have an argument.
[1:30] Then it's going to return the result of dogs as is now and it's going to let us change it. We can say delete dogs ID. Let's take a look at this. It's kind of weird. When the query starts, when we kick off our removeDog mutation, we're going to receive the ID.
[1:46] Then we're going to dispatch this very, very, very special Redux action, api.util.updateQueryData. We're updating the getDogsQuery when no argument is passed in. The way that we're going to update it is by deleting the dog with this ID.
[2:01] As soon as we start this removeDog mutation, we're immediately going to remove it from the cache which will cause our component to update even before delete dogs comes back from the server. Let's take a look at what it looks like.
[2:13] Now if you can recall, it was very slow before. Now, I'm going to go to delete one of our dogs. I'll delete Big and you can see it was removed immediately.