
本文讲解如何在 react 中为 usestate 初始数组中的每个对象(如 taskcard)分配唯一 id,避免因引用共享导致 id 冲突,并提供安全、可扩展的初始化方案。
本文讲解如何在 react 中为 usestate 初始数组中的每个对象(如 taskcard)分配唯一 id,避免因引用共享导致 id 冲突,并提供安全、可扩展的初始化方案。
在 React 开发中,使用 Array(n).fill(obj) 初始化状态数组是一个常见误区:它会创建一个包含 n 个相同对象引用的数组,而非 n 个独立对象。正如问题代码所示:
useState(Array(30).fill({id: 1, title: 'title', description: 'description'}))这会导致所有 30 个任务共享同一个 id: 1 和同一内存地址——一旦修改任一任务(例如更新标题),所有任务都会同步变化;更严重的是,removeTask 删除逻辑将失效(因 filter 依赖唯一 id,而所有 id 均为 1)。
✅ 正确做法是:为每个元素独立生成新对象。推荐使用 Array.from() 或展开运算符配合 map() 构造唯一 ID:
const [tasks, setTasks] = useState(
Array.from({ length: 30 }, (_, i) => ({
id: i + 1,
title: 'title',
description: 'description'
}))
);或等价写法(如答案所给):
const [tasks, setTasks] = useState(
[...Array(30).keys()].map(i => ({
id: i + 1,
title: 'title',
description: 'description'
}))
);? 两种方式均确保:
- 每个对象是独立实例(无引用共享);
- id 从 1 到 30 严格递增,满足 key 唯一性要求;
- 兼容后续服务端数据覆盖(useEffect 中 setTasks(res.data) 会完全替换初始数组,不影响逻辑)。
⚠️ 注意事项:
- 避免在 fill() 中传入对象字面量(fill({}))——这是“浅拷贝陷阱”;
- 若需更健壮的 ID(如防冲突、支持删除后新增),建议改用 crypto.randomUUID()(现代浏览器)或 Date.now() + Math.random() 生成字符串 ID;
- key 必须稳定且唯一,切勿使用 index 作为 key(尤其当列表存在增删操作时,会导致渲染异常和状态错乱)。
最终,完整修复后的组件如下:
import React, { useEffect, useState } from 'react';
import { getTasks } from '../api/task.api';
import { TaskCard } from './TaskCard';
export function TaskLists() {
const [tasks, setTasks] = useState(
Array.from({ length: 30 }, (_, i) => ({
id: i + 1,
title: 'title',
description: 'description'
}))
);
useEffect(() => {
async function loadTasks() {
try {
const res = await getTasks();
setTasks(res.data); // 完全覆盖初始占位数据
} catch (err) {
console.error('Failed to load tasks:', err);
}
}
loadTasks();
}, []);
const removeTask = (id) => {
setTasks(tasks.filter(task => task.id !== id));
};
return (
<div>
{tasks.map((task) => (
<TaskCard key={task.id} task={task} onDelete={removeTask} />
))}
</div>
);
}该方案兼顾初始化可靠性、可读性与可维护性,是构建动态列表组件的基础实践。

















