By implementing the PaginationBar component,
our pagination functionality is now fully working.
Our users can see all the reviews
available in the CMS,
and the next link is disabled on the last page.
Now, what we haven't done yet
is see how this new functionality
works in production.
In the ReviewsPage we're using "searchParams",
and this has some implications
on how that page will be rendered.
The Next.js documentation says that
"searchParams is a Dynamic API whose values
cannot be known ahead of time."
"Using it will opt the page into dynamic
rendering at request time."
So, by using "searchParams"
our page will be treated as dynamic.
Because it's impossible to know in advance
which values will be passed
as query string parameters,
and that's why Next.js cannot generate
static pages at build time.
Let's go and do a production build,
to see this in action.
I'll delete the ".next" folder and
do an "npm run build" as usual.
We can already see that the "/reviews"
route is dynamic:
it has a lambda symbol next to it.
Just like the documentation said,
Next.js detected that our code uses "searchParams"
and therefore it's treating that route as dynamic.
Now, let's start the production server.
If we go and reload the Reviews page,
we can see in the server logs
that it renders at runtime.
Let me clear the logs and reload it again.
It rendered page 1, that's the
one we see in the browser,
and then it also rendered page 1 again and 2.
That's because of link prefetching.
The link in the NavBar doesn't
pass the "page" parameter
so it's effectively for page 1,
and then the next link in the PaginationBar
points to page 2.
We could actually disable the NavBar link
if we're already on that page.
Anyway, if we reload,
it re-renders all the same pages again.
Because dynamic rendering
happens at every request.
Now, if we go to the next page,
it rendered pages 3 and 1,
that are the next and previous links.
It didn't actually render page 2 because
it had already been prefetched
when we loaded the first page.
And if we keep going,
it will only render the new links.
But again, if we reload the page,
it re-renders that specific page number,
along with any links found on that page.
This is the same behaviour we've seen
when we configured dynamic rendering
in the previous section.
But it's now enabled because of "searchParams".
Now, is there any way we could
use static rendering,
even for a route with pagination?
We could, but we'd need to use
a path parameter instead,
like we do for the "slug" in the ReviewPage.
Rather than passing the page number
after the question mark in the URL
we would need it to be a path segment.
We could have URLs like
"/reviews/page/1", "/reviews/page/2", and so on.
With this approach, we could then write
a "generateStaticParams" function
and return all the possible page numbers,
so Next.js can generate all
these pages statically.
This is a possible option,
and we could implement it in our application,
if we wanted.
The choice between path and "searchParams"
depends on how you look at the parameter values.
If you think of them as a
set of predefined options
then it makes sense to accept
them as path parameters
and generate them statically.
While if you see the parameters
as arbitrary values
used to generate a custom page
for that specific user
then the choice has to be dynamic searchParams.
In our example, at the moment
the page number could be seen
more like a choice between
predefined static options.
But imagine that we also plan to
add filters to the Reviews page,
allowing users to select only games
of a certain "genre" for example,
and possibly combine that with the
"platform" supported by the game,
and maybe even search by arbitrary keywords.
And the search results always
need to be paginated.
In this case, you can see how
it would be very difficult
to statically generate all the possible
combinations of search options.
This kind of URL needs to be dynamic,
because the page it generates is effectively
custom-tailored for each request.
So we'll keep using "searchParams" for pagination,
in case we want to add custom search
options to filter the reviews.
It's important to point out that
dynamic rendering doesn't necessarily mean
fetching new data at every request.
Note that we didn't configure this
page to use "force-dynamic",
like we did in the previous section when
we first looked at dynamic rendering.
If you remember, the "dynamic"
behavior defaults to "auto",
and in this case it's Next.js that automatically
decides to use dynamic rendering,
because our code reads the "searchParams".
But Next.js will still cache fetch requests,
because we didn't set any options
to disable the fetch cache.
We only set a tag used for revalidation,
and in fact the data in the cache
will still be invalidated
when Strapi calls our webhook.
But otherwise all fetch requests will be cached,
because that's the default behavior.
This is different from when
we set "force-dynamic",
because "force-dynamic" also
disables the fetch cache.
Let's see what this means in practice.
If I show you the terminal where
I have Strapi running,
as you can see Strapi logs all
the requests it receives.
Let me add a separator here, so it's
easier to see new requests.
If I go and reload the Reviews page,
you can see in the Next.js logs
that the page was rendered,
however we don't see any new
requests in the Strapi logs.
That's because Next.js is using the fetch cache.
It already had all the data displayed
on this page in the cache;
that's why it didn't send any requests to Strapi.
Every time we load this page,
Next.js re-renders it,
but all the data is already
available in the cache,
it doesn't need to be loaded from the CMS.
Rendering the page dynamically
will still be slower than returning a static file,
but it's also faster than refetching
the data from the CMS every time.
Now, if we restart from page 1,
we should see that
we can load the first 3 pages without
making any requests to Strapi,
because we already opened these pages before,
and so all the data was in the fetch cache.
But if we go to Page 4,
we didn't open this one earlier,
and that's why this time we do see some
new requests in the Strapi logs.
Most of them are for images,
which is not what we're interested in right now.
But you can see that there's
also an "/api" request,
fetching the reviews for page 5.
That may seem a bit strange,
because we opened page 4 in the browser,
but it's always because of link prefetching.
Page 5 is what the next link points to.
It didn't fetch page 4 because it had
already been requested earlier;
it was prefetched from the next link on page 3.
In fact, if we go to page 5,
it doesn't need to make any new "/api" requests
because it already fetched the data
for page 5 in the previous step.
It only loaded the image we see on this page.
Once we make a request for a certain URL
Next.js will cache and reuse the response,
so from now on it won't make any new CMS request
no matter how many times we reload page 4.
If you modify something in the CMS however,
that will trigger on-demand revalidation,
and at that point you should see that
Next.js will make new fetch
requests for all the data.
Anyway, the main point is that
even though our ReviewsPage
is rendered dynamically
the data fetched from the CMS
is still being cached.
So using "searchParams" is
not as bad for performance
as it would be without the fetch cache.