438 字
2 分钟
Next.js 在 Safari 浏览器中异常的水合错误
2025-03-04

问题描述#

我在使用 Next.js(v15.1.7) 开发时,使用 HeroUI 组件库的 ListBox 组件时,遇到了水合错误。

一开始在 Chromium 内核的浏览器中一切正常,但是当我在开发者工具中切换到移动端(iphone系列)时,发现组件使用正常但是控制台报水合错误,我一开始的第一反应是移动端代码有问题,经过排查发现并不是,而是 Next.js 在 Safari 浏览器中对于标签嵌套的渲染有问题。

水合错误

问题排查#

经过排查,发现问题出在 ListBox 和 ListItem 的标签渲染上,ListBox 默认渲染为 ul 标签,ListItem 默认渲染为 li 标签,虽然这一切看着正常,但是可能是 Next.js 在 Safari 浏览器中对于组件的渲染有问题,导致水合错误。

伪代码如下:

// Sidebar.tsx
import { Listbox, ListboxItem } from "@heroui/react";

export default function Sidebar() {
  return (
    <Listbox as="ul">
      <ListboxItem as="li" />
    </Listbox>
  )
}

解决方案#

按照如下组合尝试修改:

  • ListBox -> ul && ListboxItem -> li
  • ListBox -> ol && ListboxItem -> li
  • ListBox -> div && ListboxItem -> div
  • ListBox -> div && ListboxItem -> p
  • ListBox -> p && ListboxItem -> p

对于 chromium 内核的浏览器只有使用 p 标签嵌套 p 标签才会出现水合错误,其他标签组合则不会出现水合错误。

而对于 Safari 浏览器,则所有标签组合都会出现水合错误。

因此,可见 Next.js 在 Safari 浏览器中对于组件的渲染有问题,为了解决这个问题(在应对水合错误时,官方推荐的解决方案之一),可以使用 dynamic 组件来动态渲染组件,跳过 Next.js 的预渲染。

// Layout.tsx
import dynamic from "next/dynamic";

const Sidebar = dynamic(() => import("@/components/Sidebar"), { ssr: false });
Next.js 在 Safari 浏览器中异常的水合错误
https://www.mihouo.com/posts/front/nextjs-hydration-error-in-safari-browser/
作者
发布于
2025-03-04
许可协议
CC BY-NC-SA 4.0