At this stage our app
can display our First Post,
loading the content form a Markdown file.
Now, what if we want to add
another blog post?
We could create another Markdown file,
let's say "second-post".
And let's change the "date",
the "title" to say "Second",
and same in the body.
We can remove the rest
for this example.
Now, how do we display the data
in the new Markdown file?
We could create another page here,
but it would be very similar
to this existing FirstPostPage.
Almost all the code in this page
would stay exactly the same
when displaying a different post.
The only thing that needs to change is
the value we pass to "getPost",
that specifies which file to load.
So it would be nice to be able to reuse
the code in this page for all the posts.
We can easily rename this component
to simply "PostPage",
rather than "FirstPostPage".
And our app will still work fine,
because the name of our component
doesn't really matter,
as long as it's the default export.
But as it is this page
will still be visible only under the
"first-post" path,
because as we know the Next.js router
exposes each page based on its file name.
What if we want the same component
to be used for multiple pages under "/posts",
like a sort of wildcard match?
Next.js allows us to define "dynamic routes",
by naming this page in a special way.
We can write square brackets,
and inside that the name of the path parameter,
for example "slug".
This is a strange name for a file,
but it's perfectly legal to have
square brackets in a file name.
So the idea is that any URL
that starts with "posts/" something
will match our "posts/[slug]" page.
But we need to do something else
before this works.
We now get an error that says
"getStaticPaths is required"
"for dynamic SSG pages".
So we need to add a "getStaticPaths" function
to our code.
This is similar to "getStaticProps",
in that it must be exported and "async".
But the purpose of this function
is to tell Next.js which paths are valid
for this dynamic route.
Let's implement this function,
and you'll see what I mean.
This function returns an object
that contains a "paths" array.
And each item in this array is an object
that in turn contains a "params" object,
with parameters that identify
this specific route.
For example, in our case we want to set
a parameter called "slug",
because that's what we put
inside square brackets in the file name.
Now, we know that our existing page
was visible under "posts/first-post",
so we can set "slug" to "first-post" here.
We're basically telling Next.js
that "first-post" is one of the valid paths
for our PostPage.
But now we can add more paths,
for example add a "second-post" here.
So this way Next.js knowns that
"posts/second-post" is also a valid URL.
Now, the object returned by "getStaticPaths"
must also include a "fallback" property
that in our case we want to set to "false".
The "fallback" option tells Next.js
what to do if none of the paths above
matches the requested URL.
Setting it to false means no match
will result in a 404 Not Found page,
which is what we want in this case.
Next.js also provides
some more advanced features
where if a page doesn't exist
you can try building it on demand.
But in that case your website will
no longer be fully static.
Now, the path we set in "getStaticPaths"
will be available in "getStaticProps".
This function receives an argument
called "context".
Let's start by logging that "context"
so we'll see exactly what it contains.
Now, let me show the browser window again,
and also the server logs.
Let's reload the page,
and see what gets logged.
Here's the call to "getStaticProps()",
and the "context" object
contains some "params"
with the "slug" set to "first-post",
Let's go through what happened step by step
to make sure we understand what's going on.
In the browser we requested
the "posts/first-post" URL.
The Next.js server received the request
and matched it to our "[slug]" page,
because it's under the "posts" folder
and it's a dynamic route
so it matches anything.
But for this particular request
the "slug" parameter is set to "first-post".
Then Next.js executes
our "getStaticPaths" function
to check if "first-post" is in fact
a valid path for this page.
And it finds that it matches
the first item in our "paths" array,
so "first-post" is a valid request,
and Next.js goes on to call
the "getStaticProps" function,
passing the matching path
in the "context".
In "getStaticProps" we then load
the post data from the Markdown file,
which is then passed as props
to the component render function,
that renders the HTML as usual.
Now, what happens if we request
"second-post" instead?
The page still says "First Post",
but that's just because at the moment
we always load the same Markdown file.
If we look at the server logs however,
we can see that this time
"getStaticProps" was called
with "second-post" as the "slug" parameter.
So we should make use of
that "slug" parameter
in our "getStaticProps" function
to load the data for the right post.
Let's destructure this "context" object
and extract the "params".
In fact we could even go one level deeper
and get the "slug" directly from here.
And now, instead of always loading
the "first-post" data,
we can pass the "slug" here.
This should work because
we named our Markdown files
in the same way as our URL paths.
So if we save this change,
we can immediately see that
the page now shows the Second Post data,
so it's loading the right Markdown file.
Let's make sure everything else still works.
If we start from the "First Post",
that still shows the right content.
And if we request the "second-post",
we need to enter the path manually
because we haven't added a link to it yet,
of course that also works fine.
So that's how dynamic routes work
in Next.js.
There are a few moving parts here:
we need to name the page file
with this special square bracket syntax
to match any request under the "posts" path,
write a "getStaticPaths" function
that says which paths are actually valid,
and then use the "params" passed
in the "context" to "getStaticProps"
to load the right data.