In our application so far
we have some basic authentication functionality.
And it's working fine, but it has a few limitations.
Let's monitor the API requests.
When we load the page
we make a request to the "user" route
which returns 401 because we're not authenticated.
If we then open a product page,
this will make another request to the "user" resource.
And if we go back to the HomePage,
again this will make yet another request.
We could reduce the number of requests
we send to the API by caching the response.
So this is one possible improvement we could make.
Another thing is that,
if we look at the Sign In page,
in the code for this page
we had to create a "status" variable
to keep track of the sign in request status.
And then when we send the API request
we had to update that status
setting the "loading" and "error" flags appropriately.
This is something we need to do
pretty much whenever we make an HTTP request.
For example in our website we'll want to add
a registration page as well.
Now, I'm not actually going to write that page
because it would be very similar to this Sign In page.
But you can do that if you want to, as an exercise.
In any case, in a registration page
we would also need to handle loading and error states
just like we do here.
And it would be good to be able to do that
without having to repeat all the same code again.
So that's a second point.
Another limitation of using "useState"
and "useEffect" to make requests is that
this way this "user" data that we fetch from the API
is only available in this component.
What if we wanted to display the user details
in another component as well?
Suppose we wanted to show the user name
in the ProductPage component for example.
If we go to a product page,
maybe next to the price
we could say that this is a special offer
just for this user!
Now, this is a bit of a silly example of course,
but it is a very common requirement
to be able to share the same data
across multiple components in your app.
And there are in fact various solutions
to do what in React.
Using just the core React library
you can share some data using a Context,
or you could install one of the many
"state management" libraries, such as Redux.
But in this case the data we want to share
comes from a remote API,
and there are libraries that can help
with these very common requirements.
One of them is "SWR", which is written by Vercel,
the same company behind Next.js.
"SWR" stands for "stale-while-revalidate",
which is a reference to the fact that
when you cache some data
it will return the old or "stale" data
while it refreshes or "revalidates"
the data from the server.
Another library, that's grown massively
in popularity recently, is React Query.
Both SWR and React Query take a very similar approach,
but React Query offers a few more features,
so this is the one I'm going to show you
in our example.
So let's go and see
how to set up React Query in our application.
As usual, we'll need to install an npm package,
so I stopped the dev server,
and let me show the "dependencies" in package.json.
Now we can run "npm install react-query".
It's been installed successfully.
Let's re-launch "npm run dev".
And to use React Query we first need to
set it up globally in our application.
Something that in Next.js we can do
in the custom App component.
So here we first want to create
an instance of "QueryClient",
that is a class exported by the "react-query" module,
and provides functionality such as caching.
Then we want to make this instance available
to any component inside our App
by wrapping everything inside
a "QueryClientProvider" tag,
that I'll have to import manually.
So QueryClientProvider expects a "client" prop,
that will be the "queryClient" instance
we created above.
This way we'll be able to use
the React Query functionality
from any one of our components.
We'll see a first example of that in the next video.