ReferenceError:文档未在 Next.js 客户端组件内定义

Rom*_*kyi 0 next.js

我有一个使用 Next.js 创建的客户端组件(“使用客户端”)

"use client"

import type { ReactPortal } from "react"
import { createPortal } from "react-dom"

interface PortalProps {
  children: React.ReactNode
}

export function Portal(props: PortalProps): ReactPortal | null {
  return createPortal(props.children, document.body)
}
Run Code Online (Sandbox Code Playgroud)

每当我访问使用组件的页面时,<Portal />它都会在控制台中抛出错误

event - compiled client and server successfully in 469 ms (1685 modules)
ReferenceError: document is not defined
    at Portal (webpack-internal:///(sc_client)/./src/components/portal/portal.component.tsx:9:98)
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

PS这是我的package.json

// package.json
{
  // cut
  "next": "13.1.6"
  // cut
}
Run Code Online (Sandbox Code Playgroud)

Rom*_*kyi 5

我刚刚发现客户端组件在无法访问该document对象的服务器上进行预呈现。这就是为什么它说document is not defined

有很多修复方法的选择

  1. 包裹document检查typeof window !== undefiend以确保文档只能在浏览器环境中访问(window在预渲染期间未定义)。
  2. 使用useEffect+ useState+condition

我对问题的解决方案如下所示

"use client"

import { type ReactPortal, useEffect, useState } from "react"
import { createPortal } from "react-dom"

interface PortalProps {
  children: React.ReactNode
}

export function Portal(props: PortalProps): ReactPortal | null {
  const [isMounted, setIsMounted] = useState(false)

  useEffect(() => {
    setIsMounted(true)
  }, [])

  return isMounted ? createPortal(props.children, document.body) : null // createPortal will not be rendered on the server. Only on the client after hydration
}

Run Code Online (Sandbox Code Playgroud)

另请参阅https://beta.nextjs.org/docs/rendering/server-and-client-components#client-components

客户端组件

客户端组件使您能够向应用程序添加客户端交互性。在 Next.js 中,它们在服务器上 预渲染并在客户端上进行水化。您可以将客户端组件视为 Next.js 12 和以前版本的工作方式(即页面/目录)请参阅