更新 State 中的数组:添加、删除、替换与排序
数组是 JavaScript 中最灵活、最重要的数据结构之一。在 React 中,你经常需要将数组保存在 State 中:购物车列表、聊天消息流、待办事项清单。
就像普通对象一样,保存在 React State 中的数组也是只读的。你不应该直接调用 arr[0] = '新值',也不应该调用 push()、pop()、splice() 这类会直接变异原数组的方法。
1. 数组操作方法对照表:变异 vs 返回新数组
为了在 React 中优雅地更新数组,你需要掌握以下方法转换表:
| 操作需求 | ❌ 变异原数组(切勿在 React 中使用) | ✅ 返回全新数组(推荐在 React 中使用) |
|---|---|---|
| 添加元素 | push()、unshift() | 展开语法 [...arr, newItem] |
| 删除元素 | pop()、shift()、splice() | filter()、slice() |
| 修改/替换元素 | arr[i] = ...、splice() | map() 映射 |
| 重新排序 | sort()、reverse() | 先拷贝再排序 [...arr].sort() |
2. 向数组中添加元素
使用数组展开语法 [...arr] 创建一个新数组,并在末尾或开头插入新项:
import { useState } from 'react';
let nextId = 0;
export default function List() {
const [name, setName] = useState('');
const [artists, setArtists] = useState([]);
function handleClick() {
setArtists([
...artists, // 包含旧的所有艺术家
{ id: nextId++, name: name } // 在末尾追加新人
]);
}
return (
<>
<h1>著名雕塑家名单</h1>
<input
value={name}
onChange={e => setName(e.target.value)}
/>
<button onClick={handleClick}>添加</button>
<ul>
{artists.map(artist => (
<li key={artist.id}>{artist.name}</li>
))}
</ul>
</>
);
}
如果希望添加到列表最开头,只需颠倒顺序:[{ id: nextId++, name: name }, ...artists]。
3. 从数组中删除元素
从数组中删除某一项的最佳方式,是使用 filter() 方法——过滤掉那个不需要的项,保留剩下的所有项返回一个新数组:
function handleDelete(id) {
setArtists(
artists.filter(artist => artist.id !== id)
);
}
在这里,artist.id !== id 意味着:“只要这个人的 ID 不等于我想删除的 ID,他就留下来”。被点击的那个对象就会自然被剔除在返回的新数组之外!
4. 转换与修改数组中的元素
当你需要修改数组中的某个特定元素(例如把 ID 为 3 的待办事项标记为“已完成”),请使用 map():
function handleToggleTodo(id) {
setTodos(
todos.map(todo => {
if (todo.id === id) {
// 创建一个全新的对象,覆盖 done 属性
return { ...todo, done: !todo.done };
} else {
// 没有发生改变的其他项原样保留
return todo;
}
})
);
}
map() 会遍历每一项,当遇到要修改的那项时,返回一份拷贝了现有数据并修改了个别字段的全新对象;其余项则不受影响直接返回。
5. 对数组进行排序或反转
JavaScript 原生的 sort() 和 reverse() 是会直接修改原数组的。
如果你直接写 artists.sort(),你就变异了 State 中的原有数据!
正确的做法是:先用展开语法拷贝一份新数组,然后再对新数组进行排序:
function handleSort() {
// 1. 先用 [...list] 浅拷贝一份独立的全新数组
const nextList = [...list];
// 2. 在新数组上调用 sort()
nextList.sort((a, b) => a.title.localeCompare(b.title));
// 3. 把排序后的新数组传给 setState
setList(nextList);
}
总结
- 数组也是对象,切勿在 React State 中调用
push、splice或通过索引直接赋值; - 使用
[...arr, item]添加新元素; - 使用
arr.filter(item => item.id !== id)删除特定元素; - 使用
arr.map(item => item.id === id ? { ...item, ...updates } : item)优雅修改单项; - 使用
[...arr].sort()安全地先拷贝再排序。