66 lines
2.1 KiB
Markdown
66 lines
2.1 KiB
Markdown
---
|
||
title: Avoid Duplicate Serialization in RSC Props
|
||
impact: LOW
|
||
impactDescription: reduces network payload by avoiding duplicate serialization
|
||
tags: server, rsc, serialization, props, client-components
|
||
---
|
||
|
||
## 在 RSC Props 中避免重复序列化
|
||
|
||
**影响程度:LOW(通过避免重复序列化减少网络负载)**
|
||
|
||
RSC→client 序列化按对象引用去重,而非按值去重。相同引用 = 序列化一次;新引用 = 再次序列化。将转换操作(`.toSorted()`、`.filter()`、`.map()`)放在客户端执行,而不是服务端。
|
||
|
||
**错误做法(数组重复):**
|
||
|
||
```tsx
|
||
// RSC:发送 6 个字符串(2 个数组 × 3 个元素)
|
||
<ClientList usernames={usernames} usernamesOrdered={usernames.toSorted()} />
|
||
```
|
||
|
||
**正确做法(发送 3 个字符串):**
|
||
|
||
```tsx
|
||
// RSC:只发送一次
|
||
<ClientList usernames={usernames} />
|
||
|
||
// 客户端:在客户端进行转换
|
||
'use client'
|
||
const sorted = useMemo(() => [...usernames].sort(), [usernames])
|
||
```
|
||
|
||
**嵌套去重行为:**
|
||
|
||
去重是递归进行的。影响程度因数据类型而异:
|
||
|
||
- `string[]`、`number[]`、`boolean[]`:**HIGH 影响** - 数组及所有基本类型值完全重复
|
||
- `object[]`:**LOW 影响** - 数组结构重复,但嵌套对象按引用去重
|
||
|
||
```tsx
|
||
// string[] - 全部重复
|
||
usernames={['a','b']} sorted={usernames.toSorted()} // 发送 4 个字符串
|
||
|
||
// object[] - 仅数组结构重复
|
||
users={[{id:1},{id:2}]} sorted={users.toSorted()} // 发送 2 个数组 + 2 个唯一对象(而非 4 个)
|
||
```
|
||
|
||
**破坏去重的操作(创建新引用):**
|
||
|
||
- 数组:`.toSorted()`、`.filter()`、`.map()`、`.slice()`、`[...arr]`
|
||
- 对象:`{...obj}`、`Object.assign()`、`structuredClone()`、`JSON.parse(JSON.stringify())`
|
||
|
||
**更多示例:**
|
||
|
||
```tsx
|
||
// ❌ 错误做法
|
||
<C users={users} active={users.filter(u => u.active)} />
|
||
<C product={product} productName={product.name} />
|
||
|
||
// ✅ 正确做法
|
||
<C users={users} />
|
||
<C product={product} />
|
||
// 在客户端进行过滤/解构
|
||
```
|
||
|
||
**例外情况:** 当转换操作开销较大,或者客户端不需要原始数据时,可以传递派生数据。
|