Next.js - 带有动态路由的浅层路由

And*_*gan 17 javascript routes reactjs server-side-rendering next.js

在 Next.js 中尝试使用动态路由进行浅层路由时,页面被刷新并被忽略。似乎很多人对此感到困惑。

假设我们从下一页开始

router.push(
  '/post/[...slug]',
  '/post/2020/01/01/hello-world',
  { shallow: true }
);
Run Code Online (Sandbox Code Playgroud)

然后我们转到另一篇博文:

router.push(
  '/post/[...slug]',
  '/post/2020/01/01/foo-bar',
  { shallow: true }
);
Run Code Online (Sandbox Code Playgroud)

这个不会触发浅层路由,浏览器刷新,为什么?

在代码库中很清楚这是一个特性:

// If asked to change the current URL we should reload the current page
// (not location.reload() but reload getInitialProps and other Next.js stuffs)
// We also need to set the method = replaceState always
// as this should not go into the history (That's how browsers work)
// We should compare the new asPath to the current asPath, not the url
if (!this.urlIsNew(as)) {
  method = 'replaceState'
}
Run Code Online (Sandbox Code Playgroud)

我可以使用手动实现相同的功能,window.history.pushState()尽管这当然是一个坏主意:

window.history.pushState({
  as: '/post/2020/01/01/foo-bar',
  url: '/post/[...slug]',
  options: { shallow: true }
}, '', '/post/2020/01/01/foo-bar');
Run Code Online (Sandbox Code Playgroud)

由于 Next.JS 的内部 API 随时可能发生变化……我可能会遗漏一些东西……但为什么在这种情况下会忽略浅层?看起来很奇怪。

Ahm*_*tar 9

我认为这是预期的行为,因为您要路由到新页面。如果您只是更改查询参数,浅层路由应该可以工作,例如:

router.push('/?counter=10', undefined, { shallow: true })
Run Code Online (Sandbox Code Playgroud)

但您正在使用路由参数

router.push(
  '/post/[...slug]',
  '/post/2020/01/01/hello-world',
  { shallow: true }
);
Run Code Online (Sandbox Code Playgroud)

这表明您正在路由到一个新页面,它将卸载当前页面,加载新页面,并等待数据获取,即使我们要求进行浅路由,这在此处的文档中提到浅路由警告

顺便说一句,您说“页面已刷新”但router.push即使在没有shallow: true. 毕竟它是一个单页应用程序。它只是呈现新页面并运行getStaticProps, getServerSideProps, 或getInitialProps


Muh*_*ooq 5

浅层路由注意事项

浅层路由使您能够在不丢失状态的情况下更新路径名或查询参数,即仅更改路由的状态。但条件是,您必须位于同一页面上(如文档警告图像所示)

为此,您必须将第二个参数传递给 router.push 或 Router.push 作为未定义。否则,新页面将在卸载第一页后加载,并且您将无法获得预期的行为。

我的意思是浅层路由将不再在路径名更改方面起作用,这是因为我们选择加载新页面而不仅仅是 URL。希望这可以帮助

例子

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

// Current URL is '/'
function Page() {
  const router = useRouter()

  useEffect(() => {
    // Always do navigations after the first render
    router.push('/post/[...slug]', undefined, { shallow: true })
  }, [])

  useEffect(() => {
    // The pathname changed!
  }, [router.pathname ])
}

export default Page
Run Code Online (Sandbox Code Playgroud)