router.md 12.9 KB
Newer Older
1 2 3 4
---
description: Learn more about the API of the Next.js Router, and access the router instance in your page with the useRouter hook.
---

L
Luis Alvarez D 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# next/router

> Before moving forward, we recommend you to read [Routing Introduction](/docs/routing/introduction.md) first.

## useRouter

If you want to access the [`router` object](#router-object) inside any function component in your app, you can use the `useRouter` hook, take a look at the following example:

```jsx
import { useRouter } from 'next/router'

function ActiveLink({ children, href }) {
  const router = useRouter()
  const style = {
    marginRight: 10,
    color: router.pathname === href ? 'red' : 'black',
  }

J
Joe Haddad 已提交
23
  const handleClick = (e) => {
L
Luis Alvarez D 已提交
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
    e.preventDefault()
    router.push(href)
  }

  return (
    <a href={href} onClick={handleClick} style={style}>
      {children}
    </a>
  )
}

export default ActiveLink
```

> `useRouter` is a [React Hook](https://reactjs.org/docs/hooks-intro.html), meaning it cannot be used with classes. You can either use [withRouter](#withRouter) or wrap your class in a function component.

40
## `router` object
L
Luis Alvarez D 已提交
41 42 43

The following is the definition of the `router` object returned by both [`useRouter`](#useRouter) and [`withRouter`](#withRouter):

44
- `pathname`: `String` - Current route. That is the path of the page in `/pages`
L
Luis Alvarez D 已提交
45
- `query`: `Object` - The query string parsed to an object. It will be an empty object during prerendering if the page doesn't have [data fetching requirements](/docs/basic-features/data-fetching.md). Defaults to `{}`
46
- `asPath`: `String` - The path (including the query) shown in the browser without the configured `basePath` or `locale`.
47 48
- `isFallback`: `boolean` - Whether the current page is in [fallback mode](/docs/basic-features/data-fetching.md#fallback-pages).
- `basePath`: `String` - The active [basePath](/docs/api-reference/next.config.js/basepath.md) (if enabled).
49 50 51
- `locale`: `String` - The active locale (if enabled).
- `locales`: `String[]` - All supported locales (if enabled).
- `defaultLocale`: `String` - The current default locale (if enabled).
L
Luis Alvarez D 已提交
52

53
Additionally, the following methods are also included inside `router`:
L
Luis Alvarez D 已提交
54

55
### router.push
L
Luis Alvarez D 已提交
56 57 58 59

<details>
  <summary><b>Examples</b></summary>
  <ul>
60
    <li><a href="https://github.com/vercel/next.js/tree/canary/examples/using-router">Using Router</a></li>
L
Luis Alvarez D 已提交
61 62 63 64 65 66
  </ul>
</details>

Handles client-side transitions, this method is useful for cases where [`next/link`](/docs/api-reference/next/link.md) is not enough.

```jsx
67
router.push(url, as, options)
L
Luis Alvarez D 已提交
68 69
```

70 71
- `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
L
Luis Alvarez D 已提交
72
- `options` - Optional object with the following configuration options:
L
Luis Alvarez D 已提交
73
  - [`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`
L
Luis Alvarez D 已提交
74

75
> You don't need to use `router.push` for external URLs. [window.location](https://developer.mozilla.org/en-US/docs/Web/API/Window/location) is better suited for those cases.
L
Luis Alvarez D 已提交
76 77 78 79 80 81

#### Usage

Navigating to `pages/about.js`, which is a predefined route:

```jsx
82 83 84 85
import { useRouter } from 'next/router'

export default function Page() {
  const router = useRouter()
L
Luis Alvarez D 已提交
86

87
  return <span onClick={() => router.push('/about')}>Click me</span>
L
Luis Alvarez D 已提交
88 89 90 91 92 93
}
```

Navigating `pages/post/[pid].js`, which is a dynamic route:

```jsx
94 95 96 97
import { useRouter } from 'next/router'

export default function Page() {
  const router = useRouter()
L
Luis Alvarez D 已提交
98

99
  return <span onClick={() => router.push('/post/abc')}>Click me</span>
L
Luis Alvarez D 已提交
100 101 102
}
```

103
Redirecting the user to `pages/login.js`, useful for pages behind [authentication](/docs/authentication):
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

```jsx
import { useEffect } from 'react'
import { useRouter } from 'next/router'

// Here you would fetch and return the user
const useUser = () => ({ user: null, loading: false })

export default function Page() {
  const { user, loading } = useUser()
  const router = useRouter()

  useEffect(() => {
    if (!(user || loading)) {
      router.push('/login')
    }
  }, [user, loading])

  return <p>Redirecting...</p>
}
```

L
Luis Alvarez D 已提交
126 127
#### With URL object

128
You can use a URL object in the same way you can use it for [`next/link`](/docs/api-reference/next/link.md#with-url-object). Works for both the `url` and `as` parameters:
L
Luis Alvarez D 已提交
129 130

```jsx
131
import { useRouter } from 'next/router'
L
Luis Alvarez D 已提交
132

133
export default function ReadMore({ post }) {
134
  const router = useRouter()
L
Luis Alvarez D 已提交
135 136

  return (
137 138 139
    <span
      onClick={() => {
        router.push({
140 141
          pathname: '/post/[pid]',
          query: { pid: post.id },
142 143 144 145 146
        })
      }}
    >
      Click here to read more
    </span>
L
Luis Alvarez D 已提交
147 148
  )
}
149 150 151
```

### router.replace
L
Luis Alvarez D 已提交
152

153 154 155 156
Similar to the `replace` prop in [`next/link`](/docs/api-reference/next/link.md), `router.replace` will prevent adding a new URL entry into the `history` stack.

```jsx
router.replace(url, as, options)
L
Luis Alvarez D 已提交
157 158
```

159 160 161
- The API for `router.replace` is exactly the same as the API for [`router.push`](#router.push).

#### Usage
L
Luis Alvarez D 已提交
162

163
Take a look at the following example:
L
Luis Alvarez D 已提交
164 165

```jsx
166
import { useRouter } from 'next/router'
L
Luis Alvarez D 已提交
167

168 169
export default function Page() {
  const router = useRouter()
L
Luis Alvarez D 已提交
170

171 172 173
  return <span onClick={() => router.replace('/home')}>Click me</span>
}
```
L
Luis Alvarez D 已提交
174

175
### router.prefetch
176 177 178 179 180 181

Prefetch pages for faster client-side transitions. This method is only useful for navigations without [`next/link`](/docs/api-reference/next/link.md), as `next/link` takes care of prefetching pages automatically.

> This is a production only feature. Next.js doesn't prefetch pages on development.

```jsx
182
router.prefetch(url, as)
183 184
```

185 186
- `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
187 188 189 190 191 192 193

#### Usage

Let's say you have a login page, and after a login, you redirect the user to the dashboard. For that case, we can prefetch the dashboard to make a faster transition, like in the following example:

```jsx
import { useCallback, useEffect } from 'react'
194
import { useRouter } from 'next/router'
195 196

export default function Login() {
197
  const router = useRouter()
J
Joe Haddad 已提交
198
  const handleSubmit = useCallback((e) => {
199 200 201 202 203 204 205 206
    e.preventDefault()

    fetch('/api/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        /* Form data */
      }),
J
Joe Haddad 已提交
207
    }).then((res) => {
0
0xflotus 已提交
208
      // Do a fast client-side transition to the already prefetched dashboard page
209
      if (res.ok) router.push('/dashboard')
210 211 212 213
    })
  }, [])

  useEffect(() => {
214
    // Prefetch the dashboard page
215
    router.prefetch('/dashboard')
216 217 218 219 220 221 222 223 224 225 226
  }, [])

  return (
    <form onSubmit={handleSubmit}>
      {/* Form fields */}
      <button type="submit">Login</button>
    </form>
  )
}
```

227
### router.beforePopState
L
Luis Alvarez D 已提交
228 229 230 231

In some cases (for example, if using a [Custom Server](/docs/advanced-features/custom-server.md)), you may wish to listen to [popstate](https://developer.mozilla.org/en-US/docs/Web/Events/popstate) and do something before the router acts on it.

```jsx
232
router.beforePopState(cb)
L
Luis Alvarez D 已提交
233 234
```

235
- `cb` - The function to run on incoming `popstate` events. The function receives the state of the event as an object with the following props:
L
Luis Alvarez D 已提交
236 237
  - `url`: `String` - the route for the new state. This is usually the name of a `page`
  - `as`: `String` - the url that will be shown in the browser
238
  - `options`: `Object` - Additional options sent by [router.push](#router.push)
L
Luis Alvarez D 已提交
239

240
If `cb` returns `false`, the Next.js router will not handle `popstate`, and you'll be responsible for handling it in that case. See [Disabling file-system routing](/docs/advanced-features/custom-server.md#disabling-file-system-routing).
L
Luis Alvarez D 已提交
241

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
#### Usage

You could use `beforePopState` to manipulate the request, or force a SSR refresh, as in the following example:

```jsx
import { useEffect } from 'react'
import { useRouter } from 'next/router'

export default function Page() {
  const router = useRouter()

  useEffect(() => {
    router.beforePopState(({ url, as, options }) => {
      // I only want to allow these two routes!
      if (as !== '/' && as !== '/other') {
        // Have SSR render bad routes as a 404.
        window.location.href = as
        return false
      }

      return true
    })
  }, [])

  return <p>Welcome to the page</p>
}
```

### router.back
271

272
Navigate back in history. Equivalent to clicking the browser’s back button. It executes `window.history.back()`.
273

274 275
#### Usage

276
```jsx
277
import { useRouter } from 'next/router'
278

279 280 281 282 283
export default function Page() {
  const router = useRouter()

  return <span onClick={() => router.back()}>Click here to go back</span>
}
284 285
```

286
### router.reload
287

288
Reload the current URL. Equivalent to clicking the browser’s refresh button. It executes `window.location.reload()`.
289

290 291
#### Usage

292
```jsx
293 294 295 296
import { useRouter } from 'next/router'

export default function Page() {
  const router = useRouter()
297

298 299
  return <span onClick={() => router.reload()}>Click here to reload</span>
}
300 301
```

302
### router.events
L
Luis Alvarez D 已提交
303 304 305 306

<details>
  <summary><b>Examples</b></summary>
  <ul>
307
    <li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-loading">With a page loading indicator</a></li>
L
Luis Alvarez D 已提交
308 309 310
  </ul>
</details>

311
You can listen to different events happening inside the Next.js Router. Here's a list of supported events:
L
Luis Alvarez D 已提交
312

313 314 315
- `routeChangeStart(url, { shallow })` - Fires when a route starts to change
- `routeChangeComplete(url, { shallow })` - Fires when a route changed completely
- `routeChangeError(err, url, { shallow })` - Fires when there's an error when changing routes, or a route load is cancelled
L
Luis Alvarez D 已提交
316
  - `err.cancelled` - Indicates if the navigation was cancelled
317 318 319
- `beforeHistoryChange(url, { shallow })` - Fires just before changing the browser's history
- `hashChangeStart(url, { shallow })` - Fires when the hash will change but not the page
- `hashChangeComplete(url, { shallow })` - Fires when the hash has changed but not the page
L
Luis Alvarez D 已提交
320

321
> **Note:** Here `url` is the URL shown in the browser, including the [`basePath`](/docs/api-reference/next.config.js/basepath.md).
322 323

#### Usage
L
Luis Alvarez D 已提交
324

325
For example, to listen to the router event `routeChangeStart`, open or create `pages/_app.js` and subscribe to the event, like so:
L
Luis Alvarez D 已提交
326 327

```jsx
328 329
import { useEffect } from 'react'
import { useRouter } from 'next/router'
L
Luis Alvarez D 已提交
330

331 332
export default function MyApp({ Component, pageProps }) {
  const router = useRouter()
L
Luis Alvarez D 已提交
333

334
  useEffect(() => {
335 336 337 338 339 340
    const handleRouteChange = (url, { shallow }) => {
      console.log(
        `App is changing to ${url} ${
          shallow ? 'with' : 'without'
        } shallow routing`
      )
341
    }
L
Luis Alvarez D 已提交
342

343
    router.events.on('routeChangeStart', handleRouteChange)
L
Luis Alvarez D 已提交
344

345 346 347 348 349 350
    // If the component is unmounted, unsubscribe
    // from the event with the `off` method:
    return () => {
      router.events.off('routeChangeStart', handleRouteChange)
    }
  }, [])
L
Luis Alvarez D 已提交
351

352 353
  return <Component {...pageProps} />
}
L
Luis Alvarez D 已提交
354 355
```

356 357 358 359
> We use a [Custom App](/docs/advanced-features/custom-app.md) (`pages/_app.js`) for this example to subscribe to the event because it's not unmounted on page navigations, but you can subscribe to router events on any component in your application.

Router events should be registered when a component mounts ([useEffect](https://reactjs.org/docs/hooks-effect.html) or [componentDidMount](https://reactjs.org/docs/react-component.html#componentdidmount) / [componentWillUnmount](https://reactjs.org/docs/react-component.html#componentwillunmount)) or imperatively when an event happens.

L
Luis Alvarez D 已提交
360 361 362
If a route load is cancelled (for example, by clicking two links rapidly in succession), `routeChangeError` will fire. And the passed `err` will contain a `cancelled` property set to `true`, as in the following example:

```jsx
363 364
import { useEffect } from 'react'
import { useRouter } from 'next/router'
L
Luis Alvarez D 已提交
365

366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
export default function MyApp({ Component, pageProps }) {
  const router = useRouter()

  useEffect(() => {
    const handleRouteChangeError = (err, url) => {
      if (err.cancelled) {
        console.log(`Route to ${url} was cancelled!`)
      }
    }

    router.events.on('routeChangeError', handleRouteChangeError)

    // If the component is unmounted, unsubscribe
    // from the event with the `off` method:
    return () => {
      router.events.off('routeChangeError', handleRouteChangeError)
    }
  }, [])

  return <Component {...pageProps} />
}
L
Luis Alvarez D 已提交
387 388
```

389 390 391 392 393
## withRouter

If [`useRouter`](#useRouter) is not the best fit for you, `withRouter` can also add the same [`router` object](#router-object) to any component.

### Usage
L
Luis Alvarez D 已提交
394 395

```jsx
396
import { withRouter } from 'next/router'
L
Luis Alvarez D 已提交
397

398 399 400
function Page({ router }) {
  return <p>{router.pathname}</p>
}
L
Luis Alvarez D 已提交
401

402
export default withRouter(Page)
L
Luis Alvarez D 已提交
403
```