Skip to content

Commit

Permalink
Update link docs to reflect changes on dynamic routing (vercel#16634)
Browse files Browse the repository at this point in the history
Closes vercel#16633

- The docs and examples that use `as` have been updated to show how `href` can be used to get the same results
- Added new examples and provided more details on current examples for more details on how `href` can be used.

**Note:** With this change the usage of `as` becomes completely unrequired as I failed to find a good use case for it. Therefore documentation for `as` now includes: `Used for dynamic routes before Next.js 9.5.3`. But that should link to somewhere, either to a blog post or to the Upgrade Guide in our docs.
  • Loading branch information
lfades authored Sep 7, 2020
1 parent 4c5c7cd commit ea2df6c
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 62 deletions.
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 },
}}
>
<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

0 comments on commit ea2df6c

Please sign in to comment.