疯狂的 React key
发布: (2026年2月15日 GMT+8 22:42)
4 分钟阅读
原文: Dev.to
Source: Dev.to
通过 map 渲染
示例 1
export function Parent() {
const [array, setArray] = useState([1, 2, 3, 4, 5]);
useEffect(() => {
setTimeout(() => {
setArray((prev) => [6, 7, 8, 9, 10, ...prev]);
}, 3000);
}, []);
return (
<>
{array.map((item) => (
))}
);
}
export function Child({ item }: { item: number }) {
console.log(item);
return <>{item};
}
实验结果: 1 2 3 4 5
示例 2
export function Parent() {
const [array, setArray] = useState([1, 2, 3, 4, 5]);
useEffect(() => {
setTimeout(() => {
setArray((prev) => [6, 7, 8, 9, 10, ...prev]);
}, 3000);
}, []);
return (
<>
{array.map((_, index) => (
))}
);
}
实验结果: 6, 7, 8, 9, 10, 1, 2, 3, 4, 5
示例 3
export function Parent() {
const [array, setArray] = useState([1, 2, 3, 4, 5]);
useEffect(() => {
setTimeout(() => {
setArray((prev) => [
...prev.slice(0, 2),
10,
...prev.slice(3, prev.length),
]);
}, 3000);
}, []);
return (
<>
{array.map((item) => (
))}
);
}
export function Child({ item }: { item: number }) {
return <>{item};
}
实验结果: 10
实验 1
- 初始状态:
[1, 2, 3, 4, 5] → [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]
| 是否使用 memo | key | 渲染结果 |
|---|---|---|
| 未使用 | item | 6, 7, 8, 9, 10, 1, 2, 3, 4, 5 |
| 未使用 | index | 6, 7, 8, 9, 10, 1, 2, 3, 4, 5 |
使用 (React.memo) | item | 6, 7, 8, 9, 10 |
使用 (React.memo) | index | 6, 7, 8, 9, 10, 1, 2, 3, 4, 5 |
实验 2(值替换)
- 初始状态:
[1, 2, 3, 4, 5] → [1, 2, 10, 4, 5]
| 是否使用 memo | key | 渲染结果 |
|---|---|---|
| 未使用 | item | 1, 2, 10, 4, 5 |
| 未使用 | index | 1, 2, 10, 4, 5 |
使用 (React.memo) | item | 10 |
使用 (React.memo) | index | 1, 2, 10, 4, 5 |
结论(实验 1·2)
- 使用
React.memo时,只要 key 相同且 props 未变化,子组件就不会重新渲染。 - 不使用
React.memo时,父组件每次重新渲染,子组件都会随之重新渲染。
实验 3(数组顺序变更与状态保持)
export function Parent() {
const [array, setArray] = useState([1, 2, 3]);
useEffect(() => {
setTimeout(() => {
setArray((prev) => prev.toReversed());
}, 3000);
}, []);
return (
<>
{array.map((item) => (
))}
);
}
export function Child({ item }: { item: number }) {
const [text, setText] = useState("");
return (
<>
{item}th textfield:
setText(e.target.value)} />
);
}
结果
- 使用
key={item}时:即使数组顺序被颠倒,组件的状态也会 正确映射,随顺序变化保持对应。 - 使用
key={index}时:顺序改变后 state 与 index 绑定,导致输入的值残留在错误的位置,顺序变更无法正常反映。
最终结论
- 可以使用
index作为 key,但在数组顺序可能变化的情况下不应使用。 - key 的作用是 将组件实例与状态关联,因此应使用唯一且不变的值(如
item等),才能保证状态正确保持。