useRouter
If you want to access therouter object inside any function component in your app, you can use theuseRouter hook, take a look at the following example:
import { useRouter }from'next/router'functionActiveLink({ children, href }) {constrouter=useRouter()conststyle= { marginRight:10, color:router.asPath=== href?'red':'black', }consthandleClick= (e)=> {e.preventDefault()router.push(href) }return ( <ahref={href}onClick={handleClick}style={style}> {children} </a> )}exportdefault ActiveLink
useRouteris aReact Hook, meaning it cannot be used with classes. You can either usewithRouter or wrap your class in a function component.
router object
The following is the definition of therouter object returned by bothuseRouter andwithRouter:
pathname:String- The path for current route file that comes after/pages. Therefore,basePath,localeand trailing slash (trailingSlash: true) are not included.query:Object- The query string parsed to an object, includingdynamic route parameters. It will be an empty object during prerendering if the page doesn't useServer-side Rendering. Defaults to{}asPath:String- The path as shown in the browser including the search params and respecting thetrailingSlashconfiguration.basePathandlocaleare not included.isFallback:boolean- Whether the current page is infallback mode.basePath:String- The activebasePath (if enabled).locale:String- The active locale (if enabled).locales:String[]- All supported locales (if enabled).defaultLocale:String- The current default locale (if enabled).domainLocales:Array<{domain, defaultLocale, locales}>- Any configured domain locales.isReady:boolean- Whether the router fields are updated client-side and ready for use. Should only be used inside ofuseEffectmethods and not for conditionally rendering on the server. See related docs for use case withautomatically statically optimized pagesisPreview:boolean- Whether the application is currently inpreview mode.
Using the
asPathfield may lead to a mismatch between client and server if the page is rendered using server-side rendering orautomatic static optimization. Avoid usingasPathuntil theisReadyfield istrue.
The following methods are included insiderouter:
router.push
Handles client-side transitions, this method is useful for cases wherenext/link is not enough.
router.push(url, as, options)url:UrlObject | String- The URL to navigate to (seeNode.JS URL module documentation forUrlObjectproperties).as:UrlObject | String- 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.options- Optional object with the following configuration options:scroll- Optional boolean, controls scrolling to the top of the page after navigation. Defaults totrueshallow: Update the path of the current page without rerunninggetStaticProps,getServerSidePropsorgetInitialProps. Defaults tofalselocale- Optional string, indicates locale of the new page
You don't need to use
router.pushfor external URLs.window.location is better suited for those cases.
Navigating topages/about.js, which is a predefined route:
import { useRouter }from'next/router'exportdefaultfunctionPage() {constrouter=useRouter()return ( <buttontype="button"onClick={()=>router.push('/about')}> Click me </button> )}Navigatingpages/post/[pid].js, which is a dynamic route:
import { useRouter }from'next/router'exportdefaultfunctionPage() {constrouter=useRouter()return ( <buttontype="button"onClick={()=>router.push('/post/abc')}> Click me </button> )}Redirecting the user topages/login.js, useful for pages behindauthentication:
import { useEffect }from'react'import { useRouter }from'next/router'// Here you would fetch and return the userconstuseUser= ()=> ({ user:null, loading:false })exportdefaultfunctionPage() {const {user,loading }=useUser()constrouter=useRouter()useEffect(()=> {if (!(user|| loading)) {router.push('/login') } }, [user, loading])return <p>Redirecting...</p>}Resetting state after navigation
When navigating to the same page in Next.js, the page's statewill not be reset by default as React does not unmount unless the parent component has changed.
import Linkfrom'next/link'import { useState }from'react'import { useRouter }from'next/router'exportdefaultfunctionPage(props) {constrouter=useRouter()const [count,setCount]=useState(0)return ( <div> <h1>Page: {router.query.slug}</h1> <p>Count: {count}</p> <buttononClick={()=>setCount(count+1)}>Increase count</button> <Linkhref="/one">one</Link> <Linkhref="/two">two</Link> </div> )}In the above example, navigating between/one and/twowill not reset the count . TheuseState is maintained between renders because the top-level React component,Page, is the same.
If you do not want this behavior, you have a couple of options:
Manually ensure each state is updated using
useEffect. In the above example, that could look like:useEffect(()=> {setCount(0)}, [router.query.slug])Use a React
keytotell React to remount the component. To do this for all pages, you can use a custom app:pages/_app.jsimport { useRouter }from'next/router'exportdefaultfunctionMyApp({ Component, pageProps }) {constrouter=useRouter()return <Componentkey={router.asPath} {...pageProps} />}
With URL object
You can use a URL object in the same way you can use it fornext/link. Works for both theurl andas parameters:
import { useRouter }from'next/router'exportdefaultfunctionReadMore({ post }) {constrouter=useRouter()return ( <buttontype="button"onClick={()=> {router.push({ pathname:'/post/[pid]', query: { pid:post.id }, }) }} > Click here to read more </button> )}router.replace
Similar to thereplace prop innext/link,router.replace will prevent adding a new URL entry into thehistory stack.
router.replace(url, as, options)- The API for
router.replaceis exactly the same as the API forrouter.push.
Take a look at the following example:
import { useRouter }from'next/router'exportdefaultfunctionPage() {constrouter=useRouter()return ( <buttontype="button"onClick={()=>router.replace('/home')}> Click me </button> )}router.prefetch
Prefetch pages for faster client-side transitions. This method is only useful for navigations withoutnext/link, asnext/link takes care of prefetching pages automatically.
This is a production only feature. Next.js doesn't prefetch pages in development.
router.prefetch(url, as, options)url- The URL to prefetch, including explicit routes (e.g./dashboard) and dynamic routes (e.g./product/[id])as- Optional decorator forurl. Before Next.js 9.5.3 this was used to prefetch dynamic routes.options- Optional object with the following allowed fields:locale- allows providing a different locale from the active one. Iffalse,urlhas to include the locale as the active locale won't be used.
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:
import { useCallback, useEffect }from'react'import { useRouter }from'next/router'exportdefaultfunctionLogin() {constrouter=useRouter()consthandleSubmit=useCallback((e)=> {e.preventDefault()fetch('/api/login', { method:'POST', headers: {'Content-Type':'application/json' }, body:JSON.stringify({/* Form data */ }), }).then((res)=> {// Do a fast client-side transition to the already prefetched dashboard pageif (res.ok)router.push('/dashboard') }) }, [])useEffect(()=> {// Prefetch the dashboard pagerouter.prefetch('/dashboard') }, [router])return ( <formonSubmit={handleSubmit}> {/* Form fields */} <buttontype="submit">Login</button> </form> )}router.beforePopState
In some cases (for example, if using aCustom Server), you may wish to listen topopstate and do something before the router acts on it.
router.beforePopState(cb)cb- The function to run on incomingpopstateevents. The function receives the state of the event as an object with the following props:url:String- the route for the new state. This is usually the name of apageas:String- the url that will be shown in the browseroptions:Object- Additional options sent byrouter.push
Ifcb returnsfalse, the Next.js router will not handlepopstate, and you'll be responsible for handling it in that case. SeeDisabling file-system routing.
You could usebeforePopState to manipulate the request, or force a SSR refresh, as in the following example:
import { useEffect }from'react'import { useRouter }from'next/router'exportdefaultfunctionPage() {constrouter=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=asreturnfalse }returntrue }) }, [router])return <p>Welcome to the page</p>}router.back
Navigate back in history. Equivalent to clicking the browser’s back button. It executeswindow.history.back().
import { useRouter }from'next/router'exportdefaultfunctionPage() {constrouter=useRouter()return ( <buttontype="button"onClick={()=>router.back()}> Click here to go back </button> )}router.reload
Reload the current URL. Equivalent to clicking the browser’s refresh button. It executeswindow.location.reload().
import { useRouter }from'next/router'exportdefaultfunctionPage() {constrouter=useRouter()return ( <buttontype="button"onClick={()=>router.reload()}> Click here to reload </button> )}router.events
You can listen to different events happening inside the Next.js Router. Here's a list of supported events:
routeChangeStart(url, { shallow })- Fires when a route starts to changerouteChangeComplete(url, { shallow })- Fires when a route changed completelyrouteChangeError(err, url, { shallow })- Fires when there's an error when changing routes, or a route load is cancellederr.cancelled- Indicates if the navigation was cancelled
beforeHistoryChange(url, { shallow })- Fires before changing the browser's historyhashChangeStart(url, { shallow })- Fires when the hash will change but not the pagehashChangeComplete(url, { shallow })- Fires when the hash has changed but not the page
Good to know: Here
urlis the URL shown in the browser, including thebasePath.
For example, to listen to the router eventrouteChangeStart, open or createpages/_app.js and subscribe to the event, like so:
import { useEffect }from'react'import { useRouter }from'next/router'exportdefaultfunctionMyApp({ Component, pageProps }) {constrouter=useRouter()useEffect(()=> {consthandleRouteChange= (url, { shallow })=> {console.log(`App is changing to${url}${ shallow?'with':'without'} shallow routing` ) }router.events.on('routeChangeStart', handleRouteChange)// If the component is unmounted, unsubscribe// from the event with the `off` method:return ()=> {router.events.off('routeChangeStart', handleRouteChange) } }, [router])return <Component {...pageProps} />}We use aCustom App (
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 orcomponentDidMount /componentWillUnmount) or imperatively when an event happens.
If a route load is cancelled (for example, by clicking two links rapidly in succession),routeChangeError will fire. And the passederr will contain acancelled property set totrue, as in the following example:
import { useEffect }from'react'import { useRouter }from'next/router'exportdefaultfunctionMyApp({ Component, pageProps }) {constrouter=useRouter()useEffect(()=> {consthandleRouteChangeError= (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) } }, [router])return <Component {...pageProps} />}Thenext/compat/router export
This is the sameuseRouter hook, but can be used in bothapp andpages directories.
It differs fromnext/router in that it does not throw an error when the pages router is not mounted, and instead has a return type ofNextRouter | null.This allows developers to convert components to support running in bothapp andpages as they transition to theapp router.
A component that previously looked like this:
import { useRouter }from'next/router'constMyComponent= ()=> {const {isReady,query }=useRouter()// ...}Will error when converted over tonext/compat/router, asnull can not be destructured. Instead, developers will be able to take advantage of new hooks:
import { useEffect }from'react'import { useRouter }from'next/compat/router'import { useSearchParams }from'next/navigation'constMyComponent= ()=> {constrouter=useRouter()// may be null or a NextRouter instanceconstsearchParams=useSearchParams()useEffect(()=> {if (router&&!router.isReady) {return }// In `app/`, searchParams will be ready immediately with the values, in// `pages/` it will be available after the router is ready.constsearch=searchParams.get('search')// ... }, [router, searchParams])// ...}This component will now work in bothpages andapp directories. When the component is no longer used inpages, you can remove the references to the compat router:
import { useSearchParams }from'next/navigation'constMyComponent= ()=> {constsearchParams=useSearchParams()// As this component is only used in `app/`, the compat router can be removed.constsearch=searchParams.get('search')// ...}UsinguseRouter outside of Next.js context in pages
Another specific use case is when rendering components outside of a Next.js application context, such as insidegetServerSideProps on thepages directory. In this case, the compat router can be used to avoid errors:
import { renderToString }from'react-dom/server'import { useRouter }from'next/compat/router'constMyComponent= ()=> {constrouter=useRouter()// may be null or a NextRouter instance// ...}exportasyncfunctiongetServerSideProps() {constrenderedComponent=renderToString(<MyComponent />)return { props: { renderedComponent, }, }}Potential ESLint errors
Certain methods accessible on therouter object return a Promise. If you have the ESLint rule,no-floating-promises enabled, consider disabling it either globally, or for the affected line.
If your application needs this rule, you should eithervoid the promise – or use anasync function,await the Promise, then void the function call.This is not applicable when the method is called from inside anonClick handler.
The affected methods are:
router.pushrouter.replacerouter.prefetch
Potential solutions
import { useEffect }from'react'import { useRouter }from'next/router'// Here you would fetch and return the userconstuseUser= ()=> ({ user:null, loading:false })exportdefaultfunctionPage() {const {user,loading }=useUser()constrouter=useRouter()useEffect(()=> {// disable the linting on the next line - This is the cleanest solution// eslint-disable-next-line no-floating-promisesrouter.push('/login')// void the Promise returned by router.pushif (!(user|| loading)) {voidrouter.push('/login') }// or use an async function, await the Promise, then void the function callasyncfunctionhandleRouteChange() {if (!(user|| loading)) {awaitrouter.push('/login') } }voidhandleRouteChange() }, [user, loading])return <p>Redirecting...</p>}withRouter
IfuseRouter is not the best fit for you,withRouter can also add the samerouter object to any component.
Usage
import { withRouter }from'next/router'functionPage({ router }) {return <p>{router.pathname}</p>}exportdefaultwithRouter(Page)TypeScript
To use class components withwithRouter, the component needs to accept a router prop:
import Reactfrom'react'import { withRouter, NextRouter }from'next/router'interfaceWithRouterProps { router:NextRouter}interfaceMyComponentPropsextendsWithRouterProps {}classMyComponentextendsReact.Component<MyComponentProps> {render() {return <p>{this.props.router.pathname}</p> }}exportdefaultwithRouter(MyComponent)Was this helpful?