无废话系列之 use client ≠ client only

今儿部门新人问我:"已经在页面里写明了use client了,为什么还是报错 Hydration failed 啊?"

原因是他在代码里写了typeof window !== 'undefined'

下面我会把 为什么 use client 仍然会出现 Hydration failed 这个问题完整讲清楚,因为这是 Next.js 里非常常见的误解。

结论先说:use client ≠ 只在客户端运行

这是大家最容易误解的点。

use client 的真正含义:

"让这个组件在客户端 可以使用 React 的交互功能(如 useState/useEffect)"

组件本身仍然会在服务端执行一次来生成 HTML(SSR) ,然后再在客户端 hydration。

所以:

  • 你写了 use client
  • 但组件仍然 会在服务端运行一次(Node 环境)
  • 服务端渲染出来的 HTML 会发送给浏览器
  • 浏览器再执行相同的 React 代码进行 hydration

⚠ 因此,即使是 Client Component,它的 模块初始化代码(顶层代码)仍然会在服务器跑一次

因此:顶层使用 window 依旧会报错

你写:

ts 复制代码
if (typeof window !== 'undefined') {
  ...
}

这个语句依旧会被 服务端执行一次(因为 SSR 需要它),虽然不会崩溃,但关键问题是

SSR 输出的 HTML 与 CSR 输出的 HTML 不一致 → hydration fail

示例:

tsx 复制代码
"use client"

export default function Page() {
  let text = "hello";

  if (typeof window !== "undefined") {
    text = "hello from client";
  }

  return <div>{text}</div>;
}

服务器执行时:

  • typeof window === 'undefined'
  • text = "hello"

浏览器执行 hydration 时:

  • typeof window !== 'undefined'
  • text = "hello from client"

最终 HTML 不一致:

Server HTML Client HTML
<div>hello</div> <div>hello from client</div>

直接导致:Hydration failed

🔥 所以重点:

Client Component 依然会 SSR,因此不能在渲染逻辑里使用 window。

✔ 但可以在 useEffect 里使用,因为 effect 只在客户端执行。

推荐写法(100% 不会 Hydration failed)

如果你要用 windowdocumentlocalStorage 等:

tsx 复制代码
"use client";

import { useEffect, useState } from "react";

export default function Page() {
  const [text, setText] = useState("hello");

  useEffect(() => {
    setText("hello from client");
  }, []);

  return <div>{text}</div>;
}

✔ SSR 输出:hello

✔ 客户端 hydration 输出:hello(一致)

✔ hydration 后 useEffect 修改内容 → 不会报错

那什么时候可以用 typeof window !== 'undefined'

只能在 effect / event handler 里用

tsx 复制代码
useEffect(() => {
  if (typeof window !== 'undefined') {
    console.log(window.innerWidth);
  }
}, []);

❌ 不能用于:

  • 顶层逻辑
  • render 逻辑(JSX 里)
  • useState 初始值函数
  • 影响 SSR 输出的地方

如果真的要完全避免 SSR?

你需要 动态关闭 SSR ,而不是仅仅 use client

tsx 复制代码
const Page = dynamic(() => import("./page-client"), {
  ssr: false
});

这样组件 完全在客户端渲染,不再进行 hydration 匹配

总结(重要)

误解 正确理解
use client = only client ❌ 错
Client Component 不会在服务器执行 ❌ 会在服务器执行一次(SSR)
能直接在 JSX 或顶层使用 window ❌ 会导致 SSR/CSR 内容不一致
需要浏览器 API → 用 useEffect ✔ 正确做法
相关推荐
钟离墨笺5 分钟前
Go语言--2go基础-->基本数据类型
开发语言·前端·后端·golang
爱吃泡芙的小白白10 分钟前
Vue 3 核心原理与实战:从响应式到企业级应用
前端·javascript·vue.js
卓怡学长44 分钟前
m115乐购游戏商城系统
java·前端·数据库·spring boot·spring·游戏
老陈聊架构1 小时前
『AI辅助Skill』掌握三大AI设计Skill:前端独立完成产品设计全流程
前端·人工智能·claude·skill
Ulyanov2 小时前
从桌面到云端:构建Web三维战场指挥系统
开发语言·前端·python·tkinter·pyvista·gui开发
cypking2 小时前
二、前端Java后端对比指南
java·开发语言·前端
糠帅傅蓝烧牛肉面2 小时前
单实例多MCP聚合服务:两种实现方案深度对比
前端·docker·ai
JosieBook2 小时前
【Vue】12 Vue技术—— Vue 事件修饰符详解:掌握事件处理的高级技巧
前端·javascript·vue.js
艾斯特_3 小时前
Echarts常用配置项及解释
前端·javascript·echarts
m0_502724953 小时前
飞书真机调试
开发语言·前端·javascript