useRouter
如果需要在应用中的任何函数组件内访问 router
对象,可以使用 useRouter
钩子,参考以下示例:
useRouter
是一个 React Hook,意味着它不能与类组件一起使用。你可以使用 withRouter 或将类组件包装在函数组件中。
router
对象
以下是 useRouter
和 withRouter
返回的 router
对象的定义:
pathname
:String
- 当前路由文件在/pages
之后的路径。因此不包含basePath
、locale
和尾部斜杠 (trailingSlash: true
)。query
:Object
- 解析为对象的查询字符串,包括 动态路由 参数。如果页面未使用 服务端渲染 (SSR),则在预渲染期间为空对象。默认为{}
。asPath
:String
- 浏览器中显示的路径,包括搜索参数并遵循trailingSlash
配置。不包含basePath
和locale
。isFallback
:boolean
- 当前页面是否处于 回退模式 (fallback mode)。basePath
:String
- 当前激活的 basePath(如果启用)。locale
:String
- 当前激活的语言环境 (locale)(如果启用)。locales
:String[]
- 所有支持的语言环境(如果启用)。defaultLocale
:String
- 当前的默认语言环境(如果启用)。domainLocales
:Array<{domain, defaultLocale, locales}>
- 任何已配置的域名语言环境。isReady
:boolean
- 路由器字段是否已在客户端更新并准备就绪。应仅在useEffect
方法中使用,不可用于服务端条件渲染。相关用例请参阅 自动静态优化页面 文档。isPreview
:boolean
- 应用当前是否处于 预览模式 (preview mode)。
如果页面使用服务端渲染或 自动静态优化 (automatic static optimization),使用
asPath
字段可能导致客户端与服务端不匹配。在isReady
字段为true
之前,避免使用asPath
。
router
包含以下方法:
router.push
处理客户端导航,此方法适用于 next/link
不够用的情况。
url
:UrlObject | String
- 要导航到的 URL(UrlObject
属性请参阅 Node.JS URL 模块文档)。as
:UrlObject | String
- 可选修饰符,用于浏览器地址栏中显示的路径。Next.js 9.5.3 之前用于动态路由。options
- 可选配置对象,包含以下选项:scroll
- 可选布尔值,控制导航后是否滚动到页面顶部。默认为true
。shallow
: 更新当前页面路径而不重新运行getStaticProps
、getServerSideProps
或getInitialProps
。默认为false
。locale
- 可选字符串,指定新页面的语言环境。
外部 URL 无需使用
router.push
。window.location 更适合此类情况。
导航到预定义路由 pages/about.js
:
导航到动态路由 pages/post/[pid].js
:
将用户重定向到 pages/login.js
,适用于 身份验证 (authentication) 后的页面:
导航后重置状态
在 Next.js 中导航到同一页面时,默认情况下页面状态不会重置,因为除非父组件发生变化,否则 React 不会卸载组件。
在上例中,在 /one
和 /two
之间导航不会重置计数。useState
在渲染之间保持不变,因为顶级 React 组件 Page
是相同的。
如果不希望此行为,你有几个选择:
-
使用
useEffect
手动更新每个状态。在上例中,可以这样实现: -
使用 React
key
告诉 React 重新挂载组件。要为所有页面实现此功能,可以使用自定义应用:pages/_app.js
使用 URL 对象
可以像在 next/link
中一样使用 URL 对象。适用于 url
和 as
参数:
router.replace
类似于 next/link
中的 replace
属性,router.replace
会阻止将新 URL 添加到 history
堆栈中。
router.replace
的 API 与router.push
完全相同。
参考以下示例:
router.prefetch
预取页面以实现更快的客户端导航。此方法仅适用于没有使用 next/link
的导航,因为 next/link
会自动处理页面预取。
这是仅在生产环境中有效的功能。Next.js 在开发环境中不会预取页面。
url
- 要预取的 URL,包括显式路由(如/dashboard
)和动态路由(如/product/[id]
)。as
-url
的可选修饰符。Next.js 9.5.3 之前用于预取动态路由。options
- 可选对象,包含以下允许的字段:locale
- 允许提供与当前激活语言环境不同的语言环境。如果为false
,则url
必须包含语言环境,因为当前激活的语言环境不会被使用。
假设你有一个登录页面,登录后将用户重定向到仪表盘。对于这种情况,我们可以预取仪表盘以实现更快的跳转,如下例所示:
router.beforePopState
在某些情况下(例如使用 自定义服务器 (Custom Server)),你可能希望监听 popstate 并在路由器处理之前执行某些操作。
cb
- 在popstate
事件上运行的函数。该函数接收事件状态作为对象,包含以下属性:url
:String
- 新状态的路由。通常是page
的名称。as
:String
- 将在浏览器中显示的 URL。options
:Object
- router.push 发送的附加选项。
如果 cb
返回 false
,Next.js 路由器将不会处理 popstate
,你需要自行处理。请参阅 禁用文件系统路由 (Disabling file-system routing)。
可以使用 beforePopState
来操作请求或强制 SSR 刷新,如下例所示:
router.back
在历史记录中后退。等同于点击浏览器的后退按钮。执行 window.history.back()
。
router.reload
重新加载当前 URL。等同于点击浏览器的刷新按钮。执行 window.location.reload()
。
router.events
你可以监听 Next.js 路由器内部发生的不同事件。以下是支持的事件列表:
routeChangeStart(url, { shallow })
- 路由开始变化时触发。routeChangeComplete(url, { shallow })
- 路由完全变化后触发。routeChangeError(err, url, { shallow })
- 路由变化出错或取消时触发。err.cancelled
- 表示导航是否被取消。
beforeHistoryChange(url, { shallow })
- 浏览器历史记录变化前触发。hashChangeStart(url, { shallow })
- 哈希值将变化但页面不变时触发。hashChangeComplete(url, { shallow })
- 哈希值已变化但页面不变时触发。
须知:这里的
url
是浏览器中显示的 URL,包含basePath
。
例如,要监听 routeChangeStart
路由器事件,打开或创建 pages/_app.js
并订阅事件,如下所示:
本例使用 自定义应用 (Custom App) (
pages/_app.js
) 订阅事件,因为它在页面导航时不会卸载,但你可以在应用中的任何组件订阅路由器事件。
路由器事件应在组件挂载时(useEffect 或 componentDidMount / componentWillUnmount)或在事件发生时显式注册。
如果路由加载被取消(例如快速连续点击两个链接),routeChangeError
将触发。传递的 err
将包含设置为 true
的 cancelled
属性,如下例所示:
潜在的 ESLint 错误
router
对象上可访问的某些方法会返回 Promise。如果您启用了 ESLint 规则 no-floating-promises,可以考虑全局禁用该规则,或仅在受影响的行中禁用。
如果您的应用需要此规则,您应该使用 void
处理 Promise —— 或者使用 async
函数、await
Promise,然后 void 函数调用。当方法在 onClick
处理程序内部调用时,此方法不适用。
受影响的方法包括:
router.push
router.replace
router.prefetch
可能的解决方案
withRouter
如果 useRouter
不适合您的需求,withRouter
也可以将相同的 router
对象 添加到任何组件中。
使用方法
TypeScript
要在类组件中使用 withRouter
,组件需要接受 router 属性: