58 lines
1.9 KiB
Markdown
58 lines
1.9 KiB
Markdown
---
|
|
title: 使用 toSorted() 替代 sort() 以实现不可变性
|
|
impact: MEDIUM-HIGH
|
|
impactDescription: 防止 React 状态中的突变(mutation)错误
|
|
tags: javascript, arrays, immutability, react, state, mutation
|
|
---
|
|
|
|
## 使用 toSorted() 替代 sort() 以实现不可变性
|
|
|
|
`.sort()` 会原地(in place)修改数组,这可能导致 React 状态和属性(props)出现错误。请使用 `.toSorted()` 创建一个新的已排序数组,避免修改原数组。
|
|
|
|
**错误写法(修改了原数组):**
|
|
|
|
```typescript
|
|
function UserList({ users }: { users: User[] }) {
|
|
// 修改了 users 属性数组!
|
|
const sorted = useMemo(
|
|
() => users.sort((a, b) => a.name.localeCompare(b.name)),
|
|
[users]
|
|
)
|
|
return <div>{sorted.map(renderUser)}</div>
|
|
}
|
|
```
|
|
|
|
**正确写法(创建新数组):**
|
|
|
|
```typescript
|
|
function UserList({ users }: { users: User[] }) {
|
|
// 创建新的已排序数组,原数组不变
|
|
const sorted = useMemo(
|
|
() => users.toSorted((a, b) => a.name.localeCompare(b.name)),
|
|
[users]
|
|
)
|
|
return <div>{sorted.map(renderUser)}</div>
|
|
}
|
|
```
|
|
|
|
**为什么这在 React 中很重要:**
|
|
|
|
1. 对属性(props)/状态的修改会破坏 React 的不可变性模型——React 期望属性和状态被视为只读
|
|
2. 会导致闭包过时(stale closure)错误——在闭包(回调函数、副作用)内修改数组可能引发意外行为
|
|
|
|
**浏览器支持(旧浏览器降级方案):**
|
|
|
|
`.toSorted()` 在所有现代浏览器中可用(Chrome 110+、Safari 16+、Firefox 115+、Node.js 20+)。对于较旧的环境,请使用展开运算符:
|
|
|
|
```typescript
|
|
// 旧浏览器降级方案
|
|
const sorted = [...items].sort((a, b) => a.value - b.value)
|
|
```
|
|
|
|
**其他不可变数组方法:**
|
|
|
|
- `.toSorted()` —— 不可变排序
|
|
- `.toReversed()` —— 不可变反转
|
|
- `.toSpliced()` —— 不可变拼接
|
|
- `.with()` —— 不可变元素替换
|