Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update link docs to reflect changes on dynamic routing #16634

Merged
merged 10 commits into from
Sep 7, 2020
Merged
6 changes: 2 additions & 4 deletions docs/api-reference/next.config.js/basepath.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ description: Learn more about setting a base path in Next.js

> This feature was introduced in [Next.js 9.5](https://nextjs.org/blog/next-9-5) and up. If you’re using older versions of Next.js, please upgrade before trying it out.

To deploy a Next.js application under a sub-path of a domain you can use the `basePath` option.
To deploy a Next.js application under a sub-path of a domain you can use the `basePath` config option.

`basePath` allows you to set a path prefix for the application. For example `/docs` instead of `/` (the default).

For example, to set the base path to `/docs`, set the following configuration in `next.config.js`:
`basePath` allows you to set a path prefix for the application. For example, to use `/docs` instead of `/` (the default), open `next.config.js` and add the `basePath` config:

```js
module.exports = {
Expand Down
88 changes: 61 additions & 27 deletions docs/api-reference/next/link.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ description: Enable client-side transitions between routes with the built-in Lin

Client-side transitions between routes can be enabled via the `Link` component exported by `next/link`.

An example of linking to `/` and `/about`:
For an example, consider a `pages` directory with the following files:

- `pages/index.js`
- `pages/about.js`
- `pages/blog/[slug].js`

We can have a link to each of these pages like so:

```jsx
import Link from 'next/link'
Expand All @@ -34,6 +40,11 @@ function Home() {
<a>About Us</a>
</Link>
</li>
<li>
<Link href="/blog/hello-world">
<a>Blog Post</a>
</Link>
</li>
</ul>
)
}
Expand All @@ -43,37 +54,38 @@ export default Home

`Link` accepts the following props:

- `href` - The path inside `pages` directory. This is the only required prop
- `as` - The path that will be rendered in the browser URL bar. Used for dynamic routes
- `href` - The path or URL to navigate to. This is the only required prop
- `as` - Optional decorator for the path that will be shown in the browser URL bar. Before Next.js 9.5.3 this was used for dynamic routes, check our [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes) to see how it worked
- [`passHref`](#if-the-child-is-a-custom-component-that-wraps-an-a-tag) - Forces `Link` to send the `href` property to its child. Defaults to `false`
- `prefetch` - Prefetch the page in the background. Defaults to `true`. Any `<Link />` that is in the viewport (initially or through scroll) will be preloaded. Pages using [Static Generation](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) will preload `JSON` files with the data for faster page transitions.
- `prefetch` - Prefetch the page in the background. Defaults to `true`. Any `<Link />` that is in the viewport (initially or through scroll) will be preloaded. Pages using [Static Generation](/docs/basic-features/data-fetching.md#getstaticprops-static-generation) will preload `JSON` files with the data for faster page transitions
- [`replace`](#replace-the-url-instead-of-push) - Replace the current `history` state instead of adding a new url into the stack. Defaults to `false`
- [`scroll`](#disable-scrolling-to-the-top-of-the-page) - Scroll to the top of the page after a navigation. Defaults to `true`
- [`shallow`](/docs/routing/shallow-routing.md) - Update the path of the current page without rerunning [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation), [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering) or [`getInitialProps`](/docs/api-reference/data-fetching/getInitialProps.md). Defaults to `false`

External URLs, and any links that don't require a route navigation using `/pages`, don't need to be handled with `Link`; use the anchor tag for such cases instead.
## If the route has dynamic segments

## Dynamic routes
There is nothing special to do when linking to a [dynamic route](/docs/routing/dynamic-routes.md), including [catch all routes](/docs/routing/dynamic-routes.md#catch-all-routes), since Next.js 9.5.3 (for older versions check our [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes)). However, it can become quite common and handy to use [interpolation](/docs/routing/introduction.md#linking-to-dynamic-paths) or an [URL Object](#with-url-object) to generate the link.

A `Link` to a dynamic route is a combination of the `href` and `as` props. A link to the page `pages/post/[pid].js` will look like this:
For example, the dynamic route `pages/blog/[slug].js` will match the following link:

```jsx
<Link href="/post/[pid]" as="/post/abc">
<a>First Post</a>
</Link>
```

`href` is a file system path used by the page and it shouldn't change at runtime. `as` on the other hand, will be dynamic most of the time according to your needs. Here's an example of how to create a list of links:
import Link from 'next/link'

```jsx
const pids = ['id1', 'id2', 'id3']
{
pids.map((pid) => (
<Link href="/post/[pid]" as={`/post/${pid}`}>
<a>Post {pid}</a>
</Link>
))
function Posts({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${encodeURIComponent(post.slug)}`}>
<a>{post.title}</a>
</Link>
</li>
))}
</ul>
)
}

export default Posts
```

## If the child is a custom component that wraps an `<a>` tag
Expand Down Expand Up @@ -140,18 +152,40 @@ import Link from 'next/link'

function Home() {
return (
<div>
<Link href={{ pathname: '/about', query: { name: 'test' } }}>
<a>About us</a>
</Link>
</div>
<ul>
<li>
<Link
href={{
pathname: '/about',
query: { name: 'test' },
}}
>
<a>About us</a>
</Link>
</li>
<li>
<Link
href={{
pathname: '/blog/[slug]',
query: { slug: 'my-post' },
}}
>
<a>Blog Post</a>
</Link>
</li>
</ul>
)
}

export default Home
```

The above example will be a link to `/about?name=test`. You can use every property as defined in the [Node.js URL module documentation](https://nodejs.org/api/url.html#url_url_strings_and_url_objects).
The above example has a link to:

- A predefined route: `/about?name=test`
- A [dynamic route](/docs/routing/dynamic-routes.md): `/blog/my-post`

You can use every property as defined in the [Node.js URL module documentation](https://nodejs.org/api/url.html#url_url_strings_and_url_objects).

## Replace the URL instead of push

Expand Down
26 changes: 10 additions & 16 deletions docs/api-reference/next/router.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ Handles client-side transitions, this method is useful for cases where [`next/li
router.push(url, as, options)
```

- `url` - The URL to navigate to. This is usually the name of a `page`
- `as` - Optional decorator for the URL that will be shown in the browser. Defaults to `url`
- `url` - The URL to navigate to
- `as` - Optional decorator for the URL that will be shown in the browser. Before Next.js 9.5.3 this was used for dynamic routes, check our [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes) to see how it worked
- `options` - Optional object with the following configuration options:
- [`shallow`](/docs/routing/shallow-routing.md): Update the path of the current page without rerunning [`getStaticProps`](/docs/basic-features/data-fetching.md#getstaticprops-static-generation), [`getServerSideProps`](/docs/basic-features/data-fetching.md#getserversideprops-server-side-rendering) or [`getInitialProps`](/docs/api-reference/data-fetching/getInitialProps.md). Defaults to `false`

Expand Down Expand Up @@ -91,11 +91,7 @@ import { useRouter } from 'next/router'
export default function Page() {
const router = useRouter()

return (
<span onClick={() => router.push('/post/[pid]', '/post/abc')}>
Click me
</span>
)
return <span onClick={() => router.push('/post/abc')}>Click me</span>
}
```

Expand Down Expand Up @@ -129,15 +125,15 @@ You can use an URL object in the same way you can use it for [`next/link`](/docs
```jsx
import { useRouter } from 'next/router'

export default function ReadMore() {
export default function ReadMore({ post }) {
const router = useRouter()

return (
<span
onClick={() => {
router.push({
pathname: '/about',
query: { name: 'Vercel' },
pathname: '/post/[pid]',
query: { pid: post.id },
})
}}
>
Expand Down Expand Up @@ -181,8 +177,8 @@ Prefetch pages for faster client-side transitions. This method is only useful fo
router.prefetch(url, as)
```

- `url` - The path to a `page` inside the `pages` directory
- `as` - Optional decorator for `url`, used to prefetch [dynamic routes](/docs/routing/dynamic-routes.md). Defaults to `url`
- `url` - The URL to prefetch, that is, a path with a matching page
- `as` - Optional decorator for `url`. Before Next.js 9.5.3 this was used to prefetch dynamic routes, check our [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes) to see how it worked

#### Usage

Expand Down Expand Up @@ -210,7 +206,7 @@ export default function Login() {
}, [])

useEffect(() => {
// Prefetch the dashboard page as the user will go there after the login
// Prefetch the dashboard page
router.prefetch('/dashboard')
}, [])

Expand Down Expand Up @@ -317,9 +313,7 @@ You can listen to different events happening inside the Next.js Router. Here's a
- `hashChangeStart(url)` - Fires when the hash will change but not the page
- `hashChangeComplete(url)` - Fires when the hash has changed but not the page

> Here `url` is the URL shown in the browser. If you call `router.push(url, as)` (or similar), then the value of `url` will be `as`.
>
> **Note:** If you [configure a `basePath`](/docs/api-reference/next.config.js/basepath.md) then the value of `url` will be `basePath + as`.
> **Note:** Here `url` is the URL shown in the browser, including the [`basePath`](/docs/api-reference/next.config.js/basepath.md).

#### Usage

Expand Down
51 changes: 49 additions & 2 deletions docs/routing/dynamic-routes.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,37 @@ Multiple dynamic route segments work the same way. The page `pages/post/[pid]/[c
{ "pid": "abc", "comment": "a-comment" }
```

**Note:** Client-side navigations to a dynamic route (including [catch all routes](#catch-all-routes)) can be handled with [`next/link`](/docs/api-reference/next/link.md#dynamic-routes). Read our docs for [Linking between pages](/docs/routing/introduction.md#linking-between-pages) to learn more.
Client-side navigations to dynamic routes are handled with [`next/link`](/docs/api-reference/next/link.md). If we wanted to have links to the routes used above it will look like this:

```jsx
import Link from 'next/link'

function Home() {
return (
<ul>
<li>
<Link href="/post/abc">
<a>Go to pages/post/[pid].js</a>
</Link>
</li>
<li>
<Link href="/post/abc?foo=bar">
<a>Also goes to pages/post/[pid].js</a>
</Link>
</li>
<li>
<Link href="/post/abc/a-comment">
<a>Go to pages/post/[pid]/[comment].js</a>
</Link>
</li>
</ul>
)
}

export default Home
```

Read our docs for [Linking between pages](/docs/routing/introduction.md#linking-between-pages) to learn more.

### Catch all routes

Expand Down Expand Up @@ -108,6 +138,23 @@ The `query` objects are as follows:
- `pages/post/[pid].js` - Will match `/post/1`, `/post/abc`, etc. But not `/post/create`
- `pages/post/[...slug].js` - Will match `/post/1/2`, `/post/a/b/c`, etc. But not `/post/create`, `/post/abc`
- Pages that are statically optimized by [Automatic Static Optimization](/docs/advanced-features/automatic-static-optimization.md) will be hydrated without their route parameters provided, i.e `query` will be an empty object (`{}`).
- When routing to a dynamic route using `Link` or `router`, you will need to specify the `href` as the dynamic route, for example `/post/[pid]` and `as` as the decorator for the URL, for example `/post/abc`.

After hydration, Next.js will trigger an update to your application to provide the route parameters in the `query` object.

## Related

For more information on what to do next, we recommend the following sections:

<div class="card">
<a href="/docs/api-reference/next/link.md">
<b>Pages:</b>
<small>Enable client-side transitions with next/link.</small>
</a>
</div>

<div class="card">
<a href="/docs/routing/introduction.md">
<b>Routing:</b>
<small>Learn more about routing in Next.js.</small>
</a>
</div>
56 changes: 43 additions & 13 deletions docs/routing/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ To match a dynamic segment you can use the bracket syntax. This allows you to ma
- `pages/[username]/settings.js` → `/:username/settings` (`/foo/settings`)
- `pages/post/[...all].js` → `/post/*` (`/post/2020/id/title`)

> Check out the [Dynamic Routes documentation](/docs/routing/dynamic-routes.md) to learn more about how they work.

## Linking between pages

The Next.js router allows you to do client-side route transitions between pages, similarly to a single-page application.
Expand All @@ -54,54 +56,82 @@ function Home() {
<a>About Us</a>
</Link>
</li>
<li>
<Link href="/blog/hello-world">
<a>Blog Post</a>
</Link>
</li>
</ul>
)
}

export default Home
```

When linking to a route with [dynamic path segments](/docs/routing/dynamic-routes.md) you have to provide `href` and `as` to make sure the router knows which JavaScript file to load.
In the example above we have multiple links, each one maps a path (`href`) to a known page:

- `/` → `pages/index.js`
- `/about` → `pages/about.js`
- `/blog/hello-world` → `pages/blog/[slug].js`

### Linking to dynamic paths

- `href` - The name of the page in the `pages` directory. For example `/blog/[slug]`.
- `as` - The url that will be shown in the browser. For example `/blog/hello-world`.
You can also use interpolation to create the path, which comes in handy for [dynamic route segments](#dynamic-route-segments). For example, to show a list of posts which have been passed to the component as a prop:

```jsx
import Link from 'next/link'

function Home() {
function Posts({ posts }) {
return (
<ul>
<li>
<Link href="/blog/[slug]" as="/blog/hello-world">
<a>To Hello World Blog post</a>
</Link>
</li>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${encodeURIComponent(post.slug)}`}>
<a>{post.title}</a>
</Link>
</li>
))}
</ul>
)
}

export default Home
export default Posts
```

The `as` prop can also be generated dynamically. For example, to show a list of posts which have been passed to the page as a prop:
> [`encodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) is used in the example to keep the path utf-8 compatible.

Alternatively, using a URL Object:

```jsx
function Home({ posts }) {
import Link from 'next/link'

function Posts({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href="/blog/[slug]" as={`/blog/${post.slug}`}>
<Link
href={{
pathname: '/blog/[slug]',
query: { slug: post.slug },
lfades marked this conversation as resolved.
Show resolved Hide resolved
}}
>
<a>{post.title}</a>
</Link>
</li>
))}
</ul>
)
}

export default Posts
```

Now, instead of using interpolation to create the path, we use a URL object in `href` where:

- `pathname` is the name of the page in the `pages` directory. `/blog/[slug]` in this case.
- `query` is an object with the dynamic segment. `slug` in this case.

## Injecting the router

<details>
Expand Down