跳到主要内容

服务端与客户端边界指令

'use client' 划分的是哪一种边界?​

  • 模块边界: 文件顶部的字符串指令将该模块及其传递依赖纳入客户端模块子树,不只影响某一个 JSX 标签;
  • 传播范围: 客户端模块导入的普通模块无需每个都再写指令;
  • 执行含义: 客户端组件可以由服务器生成首屏 HTML,'use client' 不等于“完全跳过 SSR”;
"use client";

import { useState } from "react";

export function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

'use server' 怎样标记可远程调用的函数?​

  • 函数或模块: 放在服务端 async 函数体开头,或文件顶部使导出的异步函数成为 Server Functions;
  • 客户端导入: 需要客户端直接 import 时使用模块级声明,函数级声明适合在服务端定义后通过 props 传递引用;
  • 语法位置: 指令在其他语句与 import 前,可以有注释,使用单引号或双引号字符串,不用模板字符串;

跨边界传递的值有哪些限制?​

值类型Server 向 Client 传递的返回数据Server Function 参数
基本值、普通可序列化对象支持支持
Array、Map、Set、Date 等受支持内建值成员可序列化时支持成员可序列化时支持
Promise、Server Function 引用支持支持
JSX 元素可作为内容传入不作为调用参数
普通函数、DOM 节点、自定义类实例不支持不支持
  • 特殊类型: 还需区分 FormData、类型化数组等协议支持值;“可序列化”不等于仅能 JSON.stringify,也不等于所有对象都支持;
  • Symbol: 仅支持全局注册的符号,任意本地 Symbol 不能跨边界;

如何避免把整条服务端依赖带进客户端?​

  • 缩小边界: 将指令放在真正需要交互的入口,避免给页面最高层无差别添加而扩大客户端 bundle;
  • 内容组合: 用 children 传入服务端渲染内容,而不是在客户端模块中导入服务端专用实现;
  • 安全核对: 指令划分执行边界,不自动清理敏感数据,跨边界前仍要选择可公开字段;