
在 Next.js 13 的 App router 中,服务端组件向客户端组件传递 props 时需满足可序列化要求(如不能传函数),但两个客户端组件之间通信不受此限制,可直接通过 props 传递 setState 等函数实现状态同步。
在 next.js 13 的 app router 中,服务端组件向客户端组件传递 props 时需满足可序列化要求(如不能传函数),但**两个客户端组件之间通信不受此限制**,可直接通过 props 传递 `setstate` 等函数实现状态同步。
在 Next.js 13 的混合渲染模型中,一个常见误区是认为“所有客户端组件的 props 都必须可序列化”。实际上,Next.js 的官方约束仅适用于服务端组件 → 客户端组件的 props 传递:函数、date、regexp、promise 等非可序列化值禁止从 Server Component 传入 Client Component;但Client Component 之间通信完全遵循标准 React 规则——即可以自由传递函数、对象、上下文、Ref 等任意 JavaScript 值。
因此,当父组件和子组件均为客户端组件(均含 ‘use client’ 指令)时,你完全可以将 useState 返回的 setState 函数作为 prop 传递给子组件,并在子组件内安全调用:
// ChildComponent.tsx 'use client'; interface ChildProps { onChange: (e: React.ChangeEvent<HTMLSelectElement>) => void; } export default function ChildComponent({ onChange }: ChildProps) { return ( <select onChange={onChange}> <option value="A">选项 A</option> <option value="B">选项 B</option> <option value="C">选项 C</option> </select> ); }
// ParentComponent.tsx 'use client'; import { useState } from 'react'; import ChildComponent from './ChildComponent'; export default function ParentComponent() { const [selectedValue, setSelectedValue] = useState<string | null>(null); const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => { setSelectedValue(e.target.value); console.log('当前选中:', e.target.value); }; return ( <div> <h3>当前状态: {selectedValue ?? '未选择'}</h3> <ChildComponent onChange={handleSelectChange} /> </div> ); }
✅ 关键前提:确保父子组件都明确声明 ‘use client’ —— 若父组件是服务端组件(无 ‘use client’),则无法直接向子客户端组件传入 setSelectedValue,此时会触发 Error: Props must be serializable。若遇到该错误,请检查组件顶部是否遗漏了客户端指令。
⚠️ 注意事项:
- 不要尝试在 Server Component 中定义 useState 或调用 setState —— 这会导致运行时错误;
- 若需跨多个层级或复杂场景共享状态,再考虑 Context API 或 Zustand 等状态库;简单父子通信无需升级架构;
- 使用 typescript 为 onChange 添加精确类型(如示例中的 React.ChangeEvent
),可避免类型不匹配导致的隐式错误。
总结:Next.js 13 并未改变 React 的核心数据流原则。只要通信双方都是客户端组件,你就拥有完整的 React 能力 —— 包括函数传递、事件回调、状态提升等。回归基础、善用 ‘use client’ 标识,即可优雅解决绝大多数状态联动问题。