问题
Suppose I have a page
that will show the details of each chapter in the book. User can navigate to other chapters from that page, as the screen has buttons of chapters in the sidebar, and the main content shows the details of the chapter.
Now the user will navigate to that page from a list of books. At the page information, there's no chapter information of that book.
Now if the URL is \bookSlug
, so the page will show the details of the first chapter, even it is not mentioned in the URL, it will fetch the list of chapters then fetch the details of the first chapter from that list. This behaviour remains the same for URL \bookSlug\firstChapterSlug
.
So, in react-router
I used to do it like this.
<Route path={'/:bookId/:chapterId?'} component={ChapterDetails} >
And on the page, I handle the params, that id the chapterId
is undefined to just fetch the first chapter or just fetch the chapter mentioned in the chapterId param.
Now, I'm stuck here,
<Link href={'/[bookSlug]/[chapterSlug]' as={'/someBookName'} >
It is just not working, even I have marked the params in the getStaticPaths
optional GetStaticPaths<Props, {bookSlug: string, chapterSlug?: string}>
s that I can write logic.
How can I achieve that react-router behaviour here in nextJS dynamic routing?
回答1:
Since Next 9.5 you can do it by using optional catch-all routes.
You would have a route like this /[bookId]/[[...chapterId]]
.
And to navigate, since Next 9.5.3 you don't need "as" property in Link so Next sould handle this correctly :
<Link href='/some-book'/>
回答2:
Navigation like that is not possible and incorrect with nextjs, if you provide href='/[bookSlug]/[chapterSlug]'
you have to provide as='/some-book/some-chapter'
<Link href={'/[bookSlug]/[chapterSlug]' as={'/someBookName'} />
// this will produce an error
Error: The provided as value (/some-book) is incompatible with the href value (/[bookSlug]/[chapterSlug])
Possible soutions There are two possible solutions for what you are trying to achieve
If you want the route /some-book
to match with [bookSlug]
and display the page for the book details and only display some chapter you have to create an index.tsx
file which will be used to fetch only the book details and data for the first chapter and return a new page component from it. For example, this is what the pages
folder structure might look like,
- pages
- [bookSlug]
- index.tsx
- [chapterSlug].tsx
// index.tsx can be used to fetch and display the book details and first chapter
And you have to explicitly navigate to that page like below
// for navigating to /some-book (which will display only the first chapter)
<Link href='/[bookSlug]' as={'/some-book'} />
// for navigating to /some-book/some-chapter
<Link href='/[bookSlug]/[chapterSlug]' as='/some-book/some-chapter'/>
The second solution is to only keep the [bookSlug]
part of the dynamic route and fetch the book details and data for all the chapters and pass it as props. To display each chapter details page make use of shallow-routing.
When it comes to navigating to each chapter you have to make use of router.push
instead of the Link
component.
If you were thinking of conditionally returning paths
from the function getStaticPaths
where you only provide the value for param bookSlug
and omit chapterSlug
something like { paths: [{ params: { bookSlug: 'some-book'} }]}
, this will not work.
For /[bookSlug]/[chapterSlug].js
if you try to do something like that it will generate a error at build time
Error: A required parameter (chapterSlug) was not provided as a string in getStaticPaths for /[bookSlug]/[chapterSlug]
来源:https://stackoverflow.com/questions/62625134/how-can-i-specify-the-optional-parameters-in-the-dynamic-routing