We extracted this custom "useUser" hook,
so that in the NavBar we can get the "user" data
with a single line of code.
Now let's look at a another example
of using React Query.
In the SignInPage we call the "/api/login" route,
so this is another HTTP request
where we could use React Query instead.
But note that in this case it's a POST request,
not a GET like when we fetch
the user data in the NavBar.
Also, here we're only sending the request
when the user clicks the submit button,
while in the NavBar we load the user data
as soon as the component is mounted.
For these reasons, instead of "useQuery"
in this case we'll use a different hook
called "useMutation".
But by using React Query we'll also be able
to remove this "status" variable
that we added to keep track of whether
the request is "loading",
or failed with an "error".
Let's open the Sign In page,
which means we'll need to sign out first.
And we still need to refresh the page
for it to detect we're signed out.
I promise we will come back to
this issue with the Sign Out button
before the end of this section.
But anyway, we can now go to the Sign In page.
And we can start modifying our code.
As I mentioned in this case we want to call
"useMutation",
that's another hook provided by React Query.
The difference between "useQuery"
and "useMutation" is that
"useQuery" is to fetch data straight away,
and usually cache the data as well,
so typically you call "useQuery"
when you make a GET request.
While with "useMutation" we define a request here,
but we'll only execute it later,
in this case when the user clicks the submit button.
And "useMutation" is typically used
with POST requests, or maybe PUT or DELETE.
But in any case with a mutation
we are calling the API to modify,
or "mutate", some data.
While when making a "query"
we just want to GET some existing data.
Now, as argument to "useMutation" we pass
a function to make the HTTP request.
This is like the second argument
we pass to "useQuery".
But notice that with "useMutation"
we don't pass a "key" as the first argument,
because the "key" is used to cache the data
returned by the query.
But a mutation may not even return any data;
we could just DELETE an item for example.
So by default a mutation doesn't affect the cache.
Anyway, the code to make the request
will be similar to what we had in "handleSubmit",
but in this case we want to return
the data we fetch from the API.
Now, we have a single statement
inside this function,
so we could actually simplify this code a little,
and return "fetchJson" directly,
without having the function body inside brackets.
This is exactly the same thing,
but we made our code a bit shorter.
Now, "useMutation" returns an object
that unsurprisingly I'll call "mutation".
And this mutation object has various properties,
many of them similar to those
of the object returned by "useQuery".
One of these properties is "isError",
that can tell us if the request failed.
And below there's also "isLoading".
So the mutation object already includes
some "loading" and "error" flags,
similar to those we kept in this "status".
Which means we can now delete that state variable,
and instead of "status.error"
we can use "mutation.isError".
Similarly, replace "status.loading"
with "mutation.isLoading".
Both "isError" and "isLoading" are boolean values.
And since the mutation keeps track of that,
we can also remove all the calls to "setStatus".
Now, in this "catch" block
let's add a comment saying that
in this case "mutation.isError" will be true,
just to explain why we're not doing anything
in this block.
Ok. Now, we also need replace the code
that makes the HTTP request,
otherwise there's no point in using "useMutation".
The "mutation" object provides
a couple of methods to execute the request,
called "mutate" and "mutateAsync".
I pretty much always use the "async" one,
because with this we can get the response data
by "awaiting" the Promise it returns.
And I called it "user" here because
that's what this data is,
it's what the "/api/login" response contains.
Ok, so I think we're ready to save
and test if things work.
Let's try signing in, as "alice@example.com"
but let's start with a wrong password.
We get the "Invalid credentials" message,
which is correct.
And, I don't know if you noticed,
but for a split-second it also displayed
the "Loading" message
while the request was in progress.
Now, let's try with the right password,
that's "Alice123".
And we're sent to the HomePage,
which means the log in was successful.
But the NavBar still shows the "Sign In" link.
That's not quite right.
Can you guess why that may be?
As a hint, that's actually nothing to do
with the changes we made in this video.
We introduced this problem
when we changed the NavBar to use "useQuery".
What's happening is simply that
we configured "useQuery" to cache
the "user" data for 30 seconds.
So it will keep using the cached value for a while.
In the next video we'll see
how to fix this issue.
But for now, if we reload the page,
we can see that at this point we are signed in,
which means the login request succeeded.
So the request we make with the "mutation"
is working correctly.
And this is a first example of using "useMutation".
We simply pass it a function
that knows how to make the API request,
then we call "mutateAsync"
when it's time to actually send the request,
and this asynchronously returns
any data contained in the API response.
What's more is that the "mutation" object
already provides flags to detect
if the request is "loading",
or if there was an "error",
so we don't need to worry about
keeping track of those states ourselves.
In the next video we'll see how to
update the NavBar state as soon as we sign in,
fixing that problem we identified a minute ago.