We're now using "force-dynamic"
to make sure all the pages where we fetch data
display the latest content from the CMS.
This forces each page to be re-rendered at runtime
every time we request it.
Now, before we move on to
more sophisticated ways of
dealing with data changes,
there's something else we need to think about.
Given that this ReviewPage is rendered on demand
fetching the data for the given slug from the CMS,
what happens if somebody requests
a slug that doesn't exist,
like "xyz" for example?
Ideally, you'd expect our app to return a 404 page,
right?
But what actually happens at the moment
is that we see an ugly error.
If we look in the server logs,
what's happening is that
our "ReviewPage" component is rendered
with "xyz" as the slug,
but since there is no such review in the CMS
we end up with an "item" that's "undefined",
and our code fails when trying to
read its "attributes" property.
So clearlyÂ we need to handle
this error condition better.
We can use the "dev" server for this,
which in fact works similarly
to the production server
when using dynamic rendering.
The dev server shows the same error
just with a few more details,
and it also displays an overlay
window over the page,
to make sure we don't miss it.
Anyway, the problem is that in
this page we call "getReview".
In that function we call the CMS
and then take the first "item"
from the "data" array.
But if the "slug" we requested
doesn't match any reviews
then the "data" array will be empty.
So before taking the first element
we need to check if "data"
has "length" equals zero.
In this case we could simply return "null",
to indicate that there is no such review.
At this point there's still an error,
but it's no longer in this function.
We now need to update the page code as well,
and after calling "getReview"
check if we actually got a result or not.
If the "review" doesn't exist
then we should somehow return a 404 error.
We can do that by importing a special function
from the "next/navigation" module.
This provides a function called "notFound",
that we can use precisely in these situations.
We can simply call "notFound" here,
without actually returning early,
because calling this function will automatically
stop the normal rendering process,
and return a 404 page instead.
Now, we need to do this check
not just in "generateMetadata"
but also inside the function component,
because we call "getReview"
in two places in this file.
If you remember, "generateMetadata" is used
to set the "title" tag in the HTML head,
while the ReviewPage function of course
renders the main page content.
Anyway, if we save this change
we now see a 404 page in the browser.
So we are now properly handling non-existent URLs.
Note that this 404 page is the default
one provided by Next.js.
Although it is rendered inside our RootLayout.
But we can also customize the 404 page if we want.
All we need to do is create a new
file inside the "app" folder,
called "not-found.jsx".
This is a special page that will
be used for 404 responses.
Let me copy some code from the AboutPage
just as a starting point for the Not Found one.
Even though it has a special name,
this file must also export a React component.
Let me just rename it to "NotFoundPage",
and we need to import the "Heading" component.
Let's change the text to "Not Found" as well.
And then we could show a custom message here,
let's say: "Oops, the page you requested"
"only exists in a parallel universe."
Just to make our Not Found page a bit funnier.
If we try and open "/reviews/xyz" now
we can see our custom Not Found page.
Ok, so this is how we can
provide our own 404 page.
But, perhaps more importantly,
we've also seen how
we need to call the special "notFound" function
whenever we cannot render a page
because the requested data doesn't exist.