首页 > 解决方案 > 如何使用 SSG 处理 Next.js 中依赖 document.title 的代码?

问题描述

我在下面有 2 个动态 SSG 页面/blog/[slug],在这些页面中我正在渲染一个组件next/link,我可以单击这些链接转到另一个 slug,问题是我想运行一些依赖于的代码document.title,我尝试了可能的组合解决方案:

const ref = createRef<HTMLDivElement>()

useEffect(() => {
  while (ref.current?.firstChild) {
    ref.current.firstChild.remove()
  }

  const timeout = setTimeout(() => {
    if (typeof window === "object") {
      const scriptElement = document.createElement("script")
      scriptElement.src = "https://utteranc.es/client.js"
      scriptElement.async = true
      scriptElement.defer = true
      scriptElement.setAttribute("crossorigin", "annonymous")
      scriptElement.setAttribute("repo", "my/repo")
      scriptElement.setAttribute("issue-term", "title")
      scriptElement.setAttribute("theme", "photon-dark")

      ref.current?.appendChild(scriptElement)
    }
  }, 0)

  return () => {
    clearTimeout(timeout)
  }
}, [])

...

return <div ref={ref} />

问题是在页面之间切换时 useEffect 不运行,此代码仅在我访问刷新页面时有效,如何在页面之间导航时使用此代码以使其使用最新的文档标题工作?

编辑:

const BlogPost = ({
  recordMap,
  post,
  pagination,
}: InferGetStaticPropsType<typeof getStaticProps>) => {
  if (!post) {
    return null
  }

  const [script, setScript] = useState<HTMLScriptElement | null>(null)
  const ref = createRef<HTMLDivElement>()
  const router = useRouter()

  useEffect(() => {
    const handleRouteChange = () => {
      const scriptElement = document.createElement("script")
      scriptElement.src = "https://utteranc.es/client.js"
      scriptElement.async = true
      scriptElement.defer = true
      scriptElement.setAttribute("crossorigin", "annonymous")
      scriptElement.setAttribute("repo", "daniellwdb/website")
      scriptElement.setAttribute("issue-term", "title")
      scriptElement.setAttribute("theme", "photon-dark")
      setScript(scriptElement)
    }

    router.events.on("routeChangeComplete", handleRouteChange)

    return () => {
      router.events.off("routeChangeComplete", handleRouteChange)
    }
  }, [])

  useEffect(() => {
    if (script) {
      ref.current?.appendChild(script)
      setScript(null)
    } else {
      ref.current?.firstChild?.remove()
    }
  }, [script])

  return (
    <>
      <Box as="main">
        <Container maxW="2xl" mb={16}>
          <Button as={NextChakraLink} href="/" variant="link" my={8}>
             Back to home page
          </Button>
          <NotionRenderer
            className="notion-title-center"
            recordMap={recordMap}
            components={{
              // Bit of a hack to add our own component where "NotionRenderer"
              // would usually display a collection row.
              // eslint-disable-next-line react/display-name
              collectionRow: () => <BlogPostHero post={post} />,
              code: Code,
              equation: Equation,
            }}
            fullPage
            darkMode
          />
          <Pagination pagination={pagination ?? {}} />
          <Box mt={4} ref={ref} />
          <Footer />
        </Container>
      </Box>
    </>
  )
}

标签: javascriptreactjsnext.js

解决方案


您可以收听router.events

  useEffect(() => {
    const handleRouteChange = (url, { shallow }) => {
      //...
    }
    router.events.on('routeChangeComplete', handleRouteChange);

    return () => {
      router.events.off('routeChangeComplete', handleRouteChange)
    }
  }, [])

推荐阅读