使用 Next.js 访问一个页面时,为了让用户尽快看到内容,程序会经历两个阶段:
-
静态渲染(干货阶段):服务器先跑一边react,把数据填进 HTML 并发给浏览器。这时候页面上有文字、有图片有CSS样式,但此时 JavaScript 还没跑起来,所以按钮、输入框无法交互。
-
水合过程(注水阶段):浏览器下载并执行 JS 代码。React 会扫描页面上的 HTML,把事件监听器(比如 onClick)重新绑定到对应的 DOM 元素上,激活状态管理。
水合问题就是因为服务器渲染的内容和浏览器第一次渲染的内容不一致。
常见问题:
- useEffect使用不当:确保那些依赖浏览器环境(时间、本地存储、窗口大小)的代码只在客户端运行
为什么是浏览器加载 JS
浏览器跑 JS 确实是在进行渲染逻辑,但它和纯 CSR 有两个本质区别:
-
不产生新 DOM:在水合过程中,React 会尽量复用服务器发来的 HTML 节点,而不是把它们删了重建。
-
接管而非创建:它是在“接管”现有的页面。一旦水合完成,接下来的页面跳转(比如点链接跳到下一页)就会变成完全的客户端渲染,不再刷新网页。
use client
Next.js 13+ 默认所有组件都是“服务端组件 (Server Components)”。只有在需要交互时,才主动声明 use client。
当需要在页面上添加“活”的逻辑时,必须在文件最顶部写上这个指令。
运行位置:代码会在服务器渲染一次(生成 HTML),然后在浏览器再跑一次(水合)。
使用场景:
-
使用 Hooks (如 useState, useEffect, useContext)。
-
使用 浏览器 API (如 window, localStorage, document)。
-
绑定 事件监听器 (如 onClick, onChange)。
use server
用来定义服务端动作。它标记一个异步函数:这个函数虽然在前端触发,但逻辑只在服务器运行。
运行位置:只在服务器运行。
使用场景:
-
数据库操作:增删改查。
-
处理表单提交。
-
读取敏感信息:比如 API Key(不会泄露给浏览器)。