news 2026/9/9 23:35:17

OpenMontage Agent Skill 实战:避免 React Server Components Props 中的重复序列化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenMontage Agent Skill 实战:避免 React Server Components Props 中的重复序列化

OpenMontage Agent Skill 实战:避免 React Server Components Props 中的重复序列化

【免费下载链接】OpenMontageWorld's first open-source, agentic video production system. 12 production pipelines, 100+ tools, 700+ agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage

本文围绕 OpenMontage 仓库内置的 Vercel React 最佳实践技能中的一条具体规则——server-dedup-props(避免 RSC Props 中的重复序列化)展开,系统讲解 React Server Components 向客户端传输 props 时"按引用去重"的底层机制、哪些操作会破坏去重、嵌套数据的影响差异,以及如何把数据转换逻辑从服务端挪到客户端来缩减网络载荷。读完本文,你可以在评审或编写 Next.js / RSC 代码时准确识别重复序列化的反模式,并掌握一条可复制、可对照检查的优化策略。

规则定位:在 Vercel React 最佳实践体系中的位置

该规则的源文件位于 server-dedup-props.md,是 OpenMontage 仓库为 AI 编码助手(Agent)预置的一条"可加载"性能规则。从文件头部的 frontmatter 可以直接看到它在体系中的坐标:

--- title: Avoid Duplicate Serialization in RSC Props impact: LOW impactDescription: reduces network payload by avoiding duplicate serialization tags: server, rsc, serialization, props, client-components ---

结合仓库中的技能组织文档可以确认它的归属与优先级:

  • 按 SKILL.md 的分类表,server-前缀对应第 3 类"Server-Side Performance",整体影响级别为 HIGH;server-dedup-props在该类中的描述是 "Avoid duplicate serialization in RSC props"。
  • 按 _sections.md,第 3 节 Server-Side Performance 的定位是"优化服务端渲染与数据获取,消除服务端瀑布并缩短响应时间"。
  • 按 README.md 的规则文件规范,文件名采用area-description.md约定,章节由文件名前缀自动推断,影响级别分为 CRITICAL 到 LOW 共 6 档。本条规则自评 impact 为 LOW,属于"增量优化"档——它不改变正确性,而是通过避免重复序列化来减小网络载荷。
  • 这套rules/目录会被构建脚本编译进同目录的长文档 AGENTS.md,其中"避免 RSC Props 重复序列化"被编排为第 3.2 节。新规则的书写格式可参考 _template.md:frontmatter(title / impact / impactDescription / tags)+ 错误示例 + 正确示例。

换句话说,这条规则是"面向 Agent 与 LLM 的可执行知识":它要求代码生成与代码评审时,自动检查 props 中是否存在对同一数据的多次派生传递。

核心原理:RSC 序列化按"引用"而非"值"去重

规则给出的第一性原理只有两句话:

RSC→client serialization deduplicates by object reference, not value. Same reference = serialized once; new reference = serialized again. (RSC 到客户端的序列化按对象引用去重,而不是按值去重。同一引用只序列化一次;产生新引用就会被再次序列化。)

为什么这条原理如此重要?结合同目录下相邻规则 server-serialization.md 可以补全背景:React Server/Client 边界会把所有对象属性序列化成字符串,并嵌入 HTML 响应以及后续的 RSC 请求中,序列化数据直接决定页面体积与加载时间。也就是说,序列化成本是"按引用计数"的——如果你在两个 props 里传入了内容相同但引用不同的两份数据,即使值完全相等,它们也会被各序列化一遍,整份数据在网络上传输两次。

由此推出规则的核心操作准则:数据转换(.toSorted().filter().map()等)应放在客户端执行,而不是在服务端预处理好再传过去。

典型反模式与修复:从 6 个字符串降到 3 个

原文档给出的最小可复现示例如下。

错误写法(重复传输数组):

// RSC: sends 6 strings (2 arrays × 3 items) <ClientList usernames={usernames} usernamesOrdered={usernames.toSorted()} />

这里usernames假设为 3 个元素的数组。usernames.toSorted()在原地排序的同时返回了一个新数组引用,于是序列化器看到的是"两个不同的数组",把 3 个字符串各发送两遍,共 6 个字符串。

正确写法(只发送 3 个字符串):

// RSC: send once <ClientList usernames={usernames} /> // Client: transform there 'use client' const sorted = useMemo(() => [...usernames].sort(), [usernames])

要点有二:

  1. RSC 侧只传递原始数组一份,把"排序"这一派生逻辑整体下推到客户端;
  2. 客户端组件内部使用useMemo派生排序结果,依赖项为usernames引用本身——由于 props 引用在两次渲染间保持稳定,useMemo的缓存同样有效。

嵌套去重行为:影响程度取决于数据类型

规则的第二个知识点是去重是递归生效的,但不同数据类型下的浪费程度差异很大

  • string[]number[]boolean[]:影响为HIGH——数组本身 + 全部原始值(primitive)都会被完整复制一遍;
  • object[]:影响为LOW——只有数组结构本身被重复,嵌套的对象仍会按引用去重。

原文档用两行代码直观演示了这种差异:

// string[] - duplicates everything usernames={['a','b']} sorted={usernames.toSorted()} // sends 4 strings // object[] - duplicates array structure only users={[{id:1},{id:2}]} sorted={users.toSorted()} // sends 2 arrays + 2 unique objects (not 4)

解读第二行:users.toSorted()产生了一个新数组,所以"数组结构"被发了两份;但数组里的{id:1}{id:2}这两个对象引用与原数组中完全相同,因此对象本身只序列化一次,最终是"2 个数组 + 2 个唯一对象",而不是 4 份对象。这解释了为什么该规则整体标为 LOW impact:对以对象为主的数据结构,浪费主要停留在稀疏的数组壳层上;而纯原始值数组则会把内容整个翻倍,属于需要优先清理的情况。

破坏去重的操作清单

以下操作都会创建新引用,从而打破 RSC 边界上的引用去重。评审代码时可以直接对照这张清单:

数组操作(产生新数组引用):

  • .toSorted()
  • .filter()
  • .map()
  • .slice()
  • [...arr](展开语法)

对象操作(产生新对象引用):

  • {...obj}(对象展开)
  • Object.assign()
  • structuredClone()
  • JSON.parse(JSON.stringify())

一个实用推论:.toSorted()这类 ES2023 不可变方法虽然避免了就地修改的副作用(仓库同一技能在 JavaScript Performance 一节还收录了js-tosorted-immutable规则讲不可变性本身),但它必然返回新引用——在 RSC 传参场景下,"不可变方法"与"去重破坏者"是同一件事的两面。

更多常见反模式与唯一例外

原文档还给了两类高频场景的对照示例:

// ❌ Bad <C users={users} active={users.filter(u => u.active)} /> <C product={product} productName={product.name} /> // ✅ Good <C users={users} /> <C product={product} /> // Do filtering/destructuring in client

第一个例子中users.filter(...)生成了新数组引用,activeusers各序列化一份(按上文分析,若users是对象数组,则对象本身不会翻倍,但数组结构与筛选结果仍重复);正确做法是只传users,把过滤逻辑写进客户端组件。第二个例子更隐蔽:product.name看似只是一个字符串,但"把对象的字段单独拆出来作为另一个 prop 传递"同样构成冗余——客户端拿到product后完全可以自行取product.name。这提示一个通用判断标准:凡是"客户端可以从已传递数据中派生出来"的值,都不应再单独作为 prop 发送。

规则同时声明了唯一例外:

Exception:Pass derived data when transformation is expensive or client doesn't need original. (当转换开销很大、或客户端根本不需要原始数据时,才应该传递派生后的数据。)

即:如果排序/过滤在服务端计算成本显著(例如超大数据集上的重计算),或者客户端组件只消费派生结果而完全用不到原数据(此时传原数据反而是浪费),则应在服务端完成转换、只传最终派生值。这一例外与相邻规则 server-serialization.md 的"只传客户端真正用到的字段"原则正好互补——前者解决"少传字段",本规则解决"别传两份",例外条款则划出"何时该传派生值"的边界。

实践落点:如何把这条规则用起来

结合仓库中该技能的组织方式,这条规则的实际使用路径很清晰:

  1. 代码评审对照:在 Next.js / RSC 项目的 Server 组件中,逐个检查传给'use client'组件的 props——是否存在对同一数据的.toSorted()/.filter()/.map()/.slice()/ 展开派生、是否存在把嵌套字段重复拆出的"影子 props"(如product+productName);
  2. 按数据类型评估收益:纯原始值数组的重复传递优先修复(HIGH 浪费);对象数组的重复可以排后(LOW 浪费,仅数组结构重复);
  3. 修复模式固定化:把派生逻辑移入客户端组件,用useMemo包裹,依赖项写 props 引用本身;
  4. Agent 工作流集成:该技能目录(SKILL.md 声明的触发时机是"编写、评审或重构 React/Next.js 代码时")中的每条规则文件都遵循统一的"错误示例 + 正确示例 + 例外说明"结构(见 _template.md),这种结构正是为了让 LLM 能稳定地做模式匹配式的自动重构。编译产物 AGENTS.md 则提供了全部 8 个类别的完整规则索引,便于在性能优化任务中整体加载。

需要说明的适用前提:本规则讨论的是 React Server Components 向客户端组件传 props 的序列化路径,仅在 RSC 架构(如 Next.js App Router)下生效;对纯客户端 SPA 或传统 SSR,该"按引用去重"的边界并不存在,规则不适用。同时 impact 为 LOW 的定位意味着它应作为性能清单中的收尾项——在消除瀑布(async 类,CRITICAL)与缩减 bundle(bundle 类,CRITICAL)之后,再系统性清理重复序列化,以获得载荷上的增量收益。

【免费下载链接】OpenMontageWorld's first open-source, agentic video production system. 12 production pipelines, 100+ tools, 700+ agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 23:33:43

部门、项目、成本三维梳理:科技公司业财一体化的底层逻辑

在公司月度经营分析会上&#xff0c;项目经理老张当着所有人的面把报表拍在桌上&#xff1a;“这个项目的成本绝对不对&#xff0c;我这个月一共只用了两个前端工程师&#xff0c;成本明细里却挂着六个人的工资&#xff0c;另外四个人明明常年趴在研发平台组的工位上。”财务同…

作者头像 李华
网站建设 2026/9/9 23:32:26

MATLAB实现生成对抗网络(GAN):从搭建到训练的全流程代码解析

简介&#xff1a;面向深度学习初学者与GAN研究者的MATLAB实现生成对抗网络可直接运行代码包&#xff0c;解决了从零搭建GAN训练流程的入门门槛问题。压缩包含14个文件&#xff0c;其中13个.M脚本覆盖了网络初始化、前向传播、反向传播、梯度更新、激活函数及交叉熵损失等核心模…

作者头像 李华
网站建设 2026/9/9 23:31:03

C#深度学习落地实践:ONNX Runtime+YOLOv8推理完整指南

简介&#xff1a;这是一份基于Visual Studio 2013开发的C#深度学习源码示例&#xff0c;面向希望在Windows环境中快速上手深度学习的C#工程师与学生。相比常见的Linux移植版本&#xff0c;它省去配置第三方库的难题&#xff0c;安装VS2013即可直接编译运行&#xff0c;大幅降低…

作者头像 李华
网站建设 2026/9/9 23:26:48

FPGA实战:BT656接口720x576格式的Verilog实现与时序仿真

简介&#xff1a;一份基于Verilog HDL的BT656视频编码实现&#xff0c;面向FPGA开发者和数字视频接口学习者&#xff0c;解决RGB888像素格式到BT656标准数据流的转换&#xff0c;并适配720x576分辨率输出。压缩包共130个文件&#xff0c;大小约4.14MB&#xff0c;核心包含bt656…

作者头像 李华