
正规体育平台有哪些
Hyperlinks have been one of the jewels of the Web since its inception [2] . According to MDN, hyperlinks are what makes the Web, a web. While used for purposes such as linking between documents, its primary use is to reference different web pages identifiable by a unique web address or a URL [3] .
Routing is an important aspect of each web application as much as hyperlinks are to the Web. It is a mechanism through which requests are routed to the code that handles them. In relation to routing, Next.js pages are referenced and identifiable by a unique URL path. If the Web consists of navigational web pages interconnected by hyperlinks , then each Next.js app consists of route-able pages (route handlers or routes) interconnected by a router.
Next.js has built-in support for routing that can be unwieldy to unpack, especially when considering rendering and data fetching. As a prerequisite to understanding client-side routing in Next.js, it is necessary to have an overview of concepts like routing, rendering, and data fetching in Next.js.
This article will be beneficial to React developers who are familiar with Next.js and want to learn how it handles routing. You need to have a working knowledge of React and Next.js to get the most out of the article, which is solely about client-side routing and related concepts in Next.js.
Routing And Rendering
Routing and Rendering are complementary to each other and will play a huge part through the course of this article. I like how Gaurav explains [4] them:
Routing is the process through which the user is navigated to different pages on a website.
Rendering is the process of putting those pages on the UI. Every time you request a route to a particular page, you are also rendering that page, but not every render is an outcome of a route.
Take five minutes [5] to think about that.
What you need to understand about rendering in Next.js is that each page is pre-rendered [6] in advance alongside the minimal JavaScript code necessary for it to become fully interactive through a process known as hydration. How Next.js does this is highly dependent on the form of pre-rendering [7] : Static Generation or Server-side rendering , which are both highly coupled to the data fetching technique used, and separated by when the HTML for a page is generated.
Depending on your data fetching requirements, you might find yourself using built-in data fetching functions like
getStaticProps
,
getStaticPaths
, or,
getServerSideProps
, client-side data fetching tools like SWR, react-query, or traditional data fetching approaches like
fetch-on-render
[8]
,
fetch-then-render
[9]
,
render-as-you-fetch
[10]
(with
Suspense
[11]
).
Pre-rendering (before rendering — to the UI ) is complementary to Routing, and highly coupled with data fetching — a whole topic of its own in Next.js. So while these concepts are either complementary or closely related, this article will be solely focused on mere navigation between pages (routing), with references to related concepts where necessary.
With that out of the way, let’s begin with the fundamental gist: Next.js has a file-system-based router built on the concept of pages [12] .
Pages
Pages in Next.js are React Components that are automatically available as routes. They are exported as default exports from the pages directory with supported file extensions like
.js
,
.jsx
,
.ts
, or
.tsx
.
A typical Next.js app will have a folder structure with top-level directories like pages , public , and styles.
next-app ├── node_modules ├── pages │ ├── index.js // path: base-url (/) │ ├── books.jsx // path: /books │ └── book.ts // path: /book ├── public ├── styles ├── .gitignore ├── package.json └── README.md
Each page is a React component:
// pages/books.js — `base-url/book` export default function Book() { return
}
Note
:
Keep in mind that pages can also be referred to as “route handlers”.
Custom Pages
These are special pages that reside in the
pages
directory but do not participate in routing. They are prefixed with the underscore symbol, as in,
_app.js
, and
_document.js
.
-
_app.js
This is a custom component that resides in the pages folder. Next.js uses this component to initialize pages. -
_document.js
Like_app.js
,_document.js
is a custom component that Next.js uses to augment your applications
next-app ├── node_modules ├── pages │ ├── _app.js // ⚠️ Custom page (unavailable as a route) │ ├── _document.jsx // ⚠️ Custom page (unavailable as a route) │ └── index.ts // path: base-url (/) ├── public ├── styles ├── .gitignore ├── package.json └── README.md
Linking Between Pages
Next.js exposes a
Link
component from the
next/link
API that can be used to perform client-side route transitions between pages.
// Import the
component import Link from "next/link"; // This could be a page component export default function TopNav() { return (
) } // This could be a non-page component export default function Publications() { return (
{/* ... */}
) }
The
Link
component can be used inside any component, page or not. When used in its most basic form as in the example above, the
Link
component translates to a hyperlink with an
href
attribute. (More on
Link
in the next/link section below.)
Routing
Next.js file-based routing system can be used to define the most common route patterns. To accommodate for these patterns, each route is separated based on its definition.
Index Routes
By default, in your Next.js app, the initial/default route is
pages/index.js
which automatically serves as the starting point of your application as
/
. With a base URL of
localhost:3000
, this index route can be accessed at the base URL level of the application in the browser.
Index routes automatically act as the default route for each directory and can eliminate naming redundancies. The directory structure below exposes two route paths:
/
and
/home
.
next-app └── pages ├── index.js // path: base-url (/) └── home.js // path: /home
The elimination is more apparent with nested routes .
Nested Routes
A route like
pages/book
is one level deep. To go deeper is to create nested routes, which requires a nested folder structure. With a base-url of
https://www.smashingmagazine.com
, you can access the route
https://www.smashingmagazine.com/printed-books/printed-books
by creating a folder structure similar to the one below:
next-app └── pages ├── index.js // top index route └── printed-books // nested route └── printed-books.js // path: /printed-books/printed-books
Or eliminate path redundancy with index routes and access the route for printed books at
https://www.smashingmagazine.com/printed-books
.
next-app └── pages ├── index.js // top index route └── printed-books // nested route └── index.js // path: /printed-books
Dynamic routes also play an important role in eliminating redundancies.
Dynamic Routes
From the previous example we use the index route to access all printed books. To access individual books requires either creating different routes for each book like:
// ⚠️ Don't do this. next-app └── pages ├── index.js // top index route └── printed-books // nested route ├── index.js // path: /printed-books ├── typesript-in-50-lessons.js // path: /printed-books/typesript-in-50-lessons ├── checklist-cards.js // path: /printed-books/checklist-cards ├── ethical-design-handbook.js // path: /printed-books/ethical-design-handbook ├── inclusive-components.js // path: /printed-books/inclusive-components └── click.js // path: /printed-books/click
which is highly redundant, unscalable, and can be remedied with dynamic routes like:
// ✅ Do this instead. next-app └── pages ├── index.js // top index route └── printed-books ├── index.js // path: /printed-books └── [book-id].js // path: /printed-books/:book-id
The bracket syntax —
[book-id]
— is the
dynamic segment
, and is not limited to files alone. It can also be used with folders like the example below, making the author available at the route
/printed-books/:book-id/author
.
next-app └── pages ├── index.js // top index route └── printed-books ├── index.js // path: /printed-books └── [book-id] └── author.js // path: /printed-books/:book-id/author
The dynamic segment(s) of a route is exposed as a query parameter that can be accessed in any of the connecting component involved in the route with
query
object of the
useRouter()
hook — (More on this in the next/router API section).
// printed-books/:book-id import { useRouter } from 'next/router'; export default function Book() { const { query } = useRouter(); return (
book-id
{query['book-id']}
); }
// /printed-books/:book-id/author import { useRouter } from 'next/router'; export default function Author() { const { query } = useRouter(); return (
Fetch author with book-id
{query['book-id']}
); }
Extending Dynamic Route Segments With Catch All Routes
You’ve seen the dynamic route segment bracket syntax as in the previous example with
[book-id].js
. The beauty of this syntax is that it takes things even further with
Catch-All Routes
. You can infer what this does from the name: it catches all routes.
When we looked at the dynamic example, we learned how it helps eliminate file creation redundancy for a single route to access multiple books with their ID. But there’s something else we could have done.
Specifically, we had the path
/printed-books/:book-id
, with a directory structure:
next-app └── pages ├── index.js └── printed-books ├── index.js └── [book-id].js
If we updated the path to have more segments like categories, we might end up with something like:
/printed-books/design/:book-id
,
/printed-books/engineering/:book-id
, or better still
/printed-books/:category/:book-id
.
Let’s add the release year:
/printed-books/:category/:release-year/:book-id
. Can you see a pattern? The directory structure becomes:
next-app └── pages ├── index.js └── printed-books └── [category] └── [release-year] └── [book-id].js
We substituted the use of named files for dynamic routes, but somehow still ended up with another form of redundancy. Well, there’s a fix: Catch All Routes that eliminates the need for deeply nested routes:
next-app └── pages ├── index.js └── printed-books └── [...slug].js
It uses the same bracket syntax except that it is prefixed with three dots. Think of the dots like the JavaScript spread syntax. You might be wondering: If I use the catch-all routes, how do I access the category (
[category]
), and release year (
[release-year]
). Two ways:
- In the case of the printed-books example, the end goal is the book, and each book info will have its metadata attached with it, or
- The “slug” segments are returned as an array of query parameter(s).
import { useRouter } from 'next/router'; export default function Book() { const { query } = useRouter(); // There's a brief moment where `slug` is undefined // so we use the Optional Chaining (?.) and Nullish coalescing operator (??) // to check if slug is undefined, then fall back to an empty array const [category, releaseYear, bookId] = query?.slug ?? []; return (
Book Id
{bookId}
Category
{category}
Release Year
{releaseYear}
); }
Here’s more example for the route
/printed-books/[…slug]
:
Path | Query parameter |
---|---|
/printed-books/click.js
|
{ “slug”: [“click”] } |
/printed-books/2020/click.js
|
{ “slug”: [“2020”, “click”] } |
/printed-books/design/2020/click.js
|
{ “slug”: [“design”, “2020”, “click”] } |
As it is with the catch-all route, the route
/printed-books
will throw a 404 error unless you provide a fallback index route.
next-app └── pages ├── index.js └── printed-books ├── index.js // path: /printed-books └── [...slug].js
This is because the catch-all route is “strict”. It either matches a slug, or it throws an error. If you’d like to avoid creating index routes alongside catch-all routes, you can use the optional catch-all routes instead.
Extending Dynamic Route Segments With Optional Catch-All Routes
The syntax is the same as catch-all-routes, but with double square brackets instead.
next-app └── pages ├── index.js └── printed-books └── [[...slug]].js
In this case, the catch-all route (slug) is optional and if not available, fallbacks to the path
/printed-books
, rendered with
[[…slug]].js
route handler, without any query params.
Use catch-all alongside index routes, or optional catch-all routes alone. Avoid using catch-all and optional catch-all routes alongside.
Routes Precedence
The capability to be able to define the most common routing patterns can be a “black swan”. The possibility of routes clashing is a looming threat, most especially when you start getting dynamic routes worked up.
When it makes sense to do so, Next.js lets you know about route clashes in the form of errors. When it doesn’t, it applies precedence to routes according to their specificity.
For example, it is an error to have more than one dynamic route on the same level.
// ❌ This is an error // Failed to reload dynamic routes: Error: You cannot use different slug names for the // same dynamic path ('book-id' !== 'id'). next-app └── pages ├── index.js └── printed-books ├── [book-id].js └── [id].js
If you look closely at the routes defined below, you’d notice the potential for clashes.
// Directory structure flattened for simplicity next-app └── pages ├── index.js // index route (also a predefined route) └── printed-books ├── index.js ├── tags.js // predefined route ├── [book-id].js // handles dynamic route └── [...slug].js // handles catch all route
For example, try answering this: what route handles the path
/printed-books/inclusive-components
?
-
/printed-books/[book-id].js
, or -
/printed-books/[…slug].js
.
The answer lies in the “specificity” of the route handlers. Predefined routes come first, followed by dynamic routes, then catch-all routes. You can think of the route request/handling model as a pseudo-code with the following steps:
-
Is there is a
predefined route handler
that can handle the route?
-
true
— handle the route request. -
false
— go to 2.
-
-
Is there a
dynamic route handler
that can handle the route?
-
true
— handle the route request. -
false
— go to 3.
-
-
Is there a
catch-all route handler
that can handle the route?
-
true
— handle the route request. -
false
— throw a 404 page not found.
-
Therefore,
/printed-books/[book-id].js
wins.
Here are more examples:
Route | Route handler | Type of route |
---|---|---|
/printed-books
|
/printed-books
|
Index route |
/printed-books/tags
|
/printed-books/tags.js
|
Predefined route |
/printed-books/inclusive-components
|
/printed-books/[book-id].js
|
Dynamic route |
/printed-books/design/inclusive-components
|
/printed-books/[...slug].js
|
Catch-all route |
The
next/link
API
The
next/link
API exposes the
Link
component as a declarative way to perform client-side route transitions.
import Link from 'next/link' function TopNav() { return (
) }
The
Link
component will resolve to a regular HTML hyperlink. That is,
Smashing Magazine
will resolve to
Smashing Magazine
.
The
href
prop is the only required prop to the
Link
component. See the
docs
[15]
for a complete list of props available on the
Link
component.
There are other mechanisms of the
Link
component to be aware of.
Routes With Dynamic Segments
Prior to Next.js 9.5.3,
Link
ing to dynamic routes meant that you had to provide both the
href
and
as
prop to
Link
as in:
import Link from 'next/link'; const printedBooks = [ { name: 'Ethical Design', id: 'ethical-design' }, { name: 'Design Systems', id: 'design-systems' }, ]; export default function PrintedBooks() { return printedBooks.map((printedBook) => (
{printedBook.name}
)); }
Although this allowed Next.js to interpolate the href for the dynamic parameters, it was tedious, error-prone, and somewhat imperative, and has now been fixed for the majority of use-cases with the release of Next.js 10.
This fix is also backward compatible. If you have been using both
as
and
href
, nothing breaks. To adopt the new syntax, discard the
href
prop and its value, and rename the
as
prop to
href
as in the example below:
import Link from 'next/link'; const printedBooks = [ { name: 'Ethical Design', id: 'ethical-design' }, { name: 'Design Systems', id: 'design-systems' }, ]; export default function PrintedBooks() { return printedBooks.map((printedBook) => (
{printedBook.name}
)); }
Use-cases For The
passHref
Prop
Take a close look at the snippet below:
import Link from 'next/link'; const printedBooks = [ { name: 'Ethical Design', id: 'ethical-design' }, { name: 'Design Systems', id: 'design-systems' }, ]; // Say this has some sort of base styling attached function CustomLink({ href, name }) { return
{name}
; } export default function PrintedBooks() { return printedBooks.map((printedBook) => (
)); }
The
passHref
props force the
Link
component to pass the
href
prop down to the
CustomLink
child component. This is compulsory if the
Link
component wraps over a component that returns a hyperlink
tag. Your use-case might be because you are using a library like styled-components, or if you need to pass multiple children to the
Link
component, as it only expects a single child.
URL Objects
The
href
prop of the
Link
component can also be a URL object with properties like
query
which is automatically formatted into a URL string.
With the
printedBooks
object, the example below will link to:
-
/printed-books/ethical-design?name=Ethical+Design
and -
/printed-books/design-systems?name=Design+Systems
.
import Link from 'next/link'; const printedBooks = [ { name: 'Ethical Design', id: 'ethical-design' }, { name: 'Design Systems', id: 'design-systems' }, ]; export default function PrintedBooks() { return printedBooks.map((printedBook) => (
{printedBook.name}
)); }
If you include a dynamic segment in the
pathname
, then you must also include it as a property in the query object to make sure the query is interpolated in the
pathname
:
import Link from 'next/link'; const printedBooks = [ { name: 'Ethical Design', id: 'ethical-design' }, { name: 'Design Systems', id: 'design-systems' }, ]; // In this case the dynamic segment `[book-id]` in pathname // maps directly to the query param `book-id` export default function PrintedBooks() { return printedBooks.map((printedBook) => (
{printedBook.name}
)); }
The example above have paths:
-
/printed-books/ethical-design
, and -
/printed-books/design-systems
.
If you inspect the
href
attribute in VSCode, you’d find the type
LinkProps
, with the
href
property a
Url
type, which is either a
string
or
UrlObject
as mentioned previously.

LinkProps
in VSCode. (
Large preview
[18]
)
Inspecting the
UrlObject
further leads to the interface with the properties:

You can learn more about these properties in the Node.js URL module documentation [20] .
One use case of the hash is to link to specific sections in a page.
import Link from 'next/link'; const printedBooks = [{ name: 'Ethical Design', id: 'ethical-design' }]; export default function PrintedBooks() { return printedBooks.map((printedBook) => (
{printedBook.name}
)); }
The hyperlink will resolve to
/printed-books/ethical-design#faq
.
The
next/router
API
If the
next/link
is declarative, then the
next/router
is imperative. It exposes a
useRouter
hook that allows access to the
router
[22]
object inside any function component. You can use this hook to manually perform routing, most especially in certain scenarios where the
next/link
is not enough, or where you need to “hook” into the routing.
import { useRouter } from 'next/router'; export default function Home() { const router = useRouter(); function handleClick(e) { e.preventDefault(); router.push(href); } return (
) }
useRouter
is a React hook and cannot be used with classes. Need the
router
object in class components? Use
withRouter
.
import { withRouter } from 'next/router'; function Home({router}) { function handleClick(e) { e.preventDefault(); router.push(href); } return (
) } export default withRouter(Home);
The
router
Object
Both the
useRouter
hook and
withRouter
higher-order component, return a router object with properties like
pathname
,
query
,
asPath
, and
basePath
that gives you information about the URL state of the current page,
locale
,
locales
, and
defaultLocale
that gives information about the active, supported, or current default locale.
The router object also has methods like
push
for navigating to a new URL by adding a new URL entry into the history stack,
replace
, similar to push but replaces the current URL instead of adding a new URL entry into the history stack.
Learn more about the router object [23] .
Custom Route Configuration With
next.config.js
This is a regular Node.js module that can be used to configure certain Next.js behavior.
module.exports = { // configuration options }
Remember to restart your server anytime you update
next.config.js
. Learn more [24] .
Base Path
It was mentioned that the initial/default route in Next.js is
pages/index.js
with path
/
. This is configurable and you can make your default route a sub-path of the domain.
module.exports = { // old default path: / // new default path: /dashboard basePath: '/dashboard', };
These changes will automatically take effect in your application with all
/
paths routed to
/dashboard
.
This feature can only be used with Next.js 9.5 and above. Learn more [25] .
Trailing Slash
By default, a trailing slash will not be available at the end of each URL. However, you can switch that with:
module.exports = { trailingSlash: true };
# trailingSlash: false /printed-books/ethical-design#faq # trailingSlash: true /printed-books/ethical-design/#faq
Both the base path [26] and trailing slash [27] features can only be used with Next.js 9.5 and above.
Conclusion
Routing is one of the most important parts of your Next.js application, and it reflects in the file-system-based router built on the concept of pages. Pages can be used to define the most common route patterns. The concepts of routing and rendering are closely related. Take the lessons of this article with you as you build your own Next.js app or work on a Next.js codebase. And check the resources below to learn more.
Related Resources

References
- ^ More about Adebiyi ↬ (www.smashingmagazine.com)
- ^ since its inception (developer.mozilla.org)
- ^ URL (developer.mozilla.org)
- ^ Gaurav explains (www.pluralsight.com)
- ^ Take five minutes (signalvnoise.com)
- ^ pre-rendered (nextjs.org)
- ^ form of pre-rendering (nextjs.org)
- ^ fetch-on-render (reactjs.org)
- ^ fetch-then-render (reactjs.org)
- ^ render-as-you-fetch (reactjs.org)
- ^ Suspense (reactjs.org)
- ^ concept of pages (nextjs.org)
- ^ Successful Design Systems (smashingconf.com)
- ^ Jump to the workshop ↬ (smashingconf.com)
- ^ docs (nextjs.org)
- ^ Automatic resolving of href (nextjs.org)
- ^ docs (nextjs.org)
- ^ Large preview (cloud.netlifyusercontent.com)
- ^ Large preview (cloud.netlifyusercontent.com)
- ^ Node.js URL module documentation (nodejs.org)
- ^ the docs (nextjs.org)
- ^ router (nextjs.org)
- ^ router object (nextjs.org)
- ^ Learn more (nextjs.org)
- ^ Learn more (nextjs.org)
- ^ base path (nextjs.org)
- ^ trailing slash (nextjs.org)
Powered by WPeMatico