我想从列表中删除所选项目。
当我点击删除正确的项目时,会从列表内容中删除,但在 UI 上,我总是会触发列表项目。
我似乎在跟踪 JSX keys
并显示最后的值。
这是一个demo
const Holidays = (props) => {
console.log(props);
const [state, setState] = useState({ ...props });
useEffect(() => {
setState(props);
console.log(state);
}, []);
const addNewHoliday = () => {
const obj = { start: "12/12", end: "12/13" };
setState(update(state, { daysOffList: { $push: [obj] } }));
};
const deleteHoliday = (i) => {
const objects = state.daysOffList.filter((elm, index) => index != i);
console.log({ objects });
setState(update(state, { daysOffList: { $set: objects } }));
console.log(state.daysOffList);
};
return (
<>
<Header as="h1" content="Select Holidays" />
<Button
primary
icon={<AddIcon />}
text
content="Add new holidays"
onClick={() => addNewHoliday(state)}
/>
{state?.daysOffList?.map((elm, i) => {
console.log(elm.end);
return (
<Flex key={i.toString()} gap="gap.small">
<>
<Header as="h5" content="Start Date" />
<Datepicker
defaultSelectedDate={
new Date(`${elm.start}/${new Date().getFullYear()}`)
}
/>
</>
<>
<Header as="h5" content="End Date" />
<Datepicker
defaultSelectedDate={
new Date(`${elm.end}/${new Date().getFullYear()}`)
}
/>
</>
<Button
key={i.toString()}
primary
icon={<TrashCanIcon />}
text
onClick={() => deleteHoliday(i)}
/>
<span>{JSON.stringify(state.daysOffList)}</span>
</Flex>
);
})}
</>
);
};
export default Holidays;
更新
我正在尝试通过添加时间戳来制作 uniq id。
return (
<Flex key={`${JSON.stringify(elm)} ${Date.now()}`} gap="gap.small">
<>
<Header as="h5" content="Start Date" />
<Datepicker
defaultSelectedDate={
new Date(`${elm.start}/${new Date().getFullYear()}`)
}
/>
</>
<>
<Header as="h5" content="End Date" />
<Datepicker
defaultSelectedDate={
new Date(`${elm.end}/${new Date().getFullYear()}`)
}
/>
</>
<Button
primary
key={`${JSON.stringify(elm)} ${Date.now()}`}
icon={<TrashCanIcon />}
text
onClick={() => deleteHoliday(i)}
/>{" "}
</Flex>
);
我希望错误消失但仍然得到相同的行为
答案 0 :(得分:1)
您使用数组索引作为 React 键并且您正在改变底层数据数组。当您单击第二个条目将其删除时,第三个元素向前移动以填补空白,现在为刚刚删除的元素分配 React 键。 React 使用密钥来帮助协调,如果密钥保持稳定,React 会重新渲染 UI。
您也不能在队列状态更新后立即控制台日志状态并期望看到更新的状态。
setState(update(state, { daysOffList: { $set: objects } }));
console.log(state.daysOffList);
React 状态更新是异步的,并且在 渲染周期之间进行处理。以上可以并且将只记录当前渲染周期的状态值,而不是为下一个排队的更新 渲染周期。
为每个开始/结束数据对象使用 GUID。 uuid 是一个非常棒的包,并且具有非常好的唯一性保证并且使用起来非常简单。
import { v4 as uuidV4 } from 'uuid';
// generate unique id
uuidV4();
要专门解决代码中的问题:
向您的数据添加 id
属性
const daysOffList = [
{ id: uuidV4(), start: "12/12", end: "12/15" },
{ id: uuidV4(), start: "12/12", end: "12/17" },
{ id: uuidV4(), start: "12/12", end: "12/19" }
];
...
const addNewHoliday = () => {
const obj = {
id: uuidV4(),
start: "12/12",
end: "12/13",
};
setState(update(state, { daysOffList: { $push: [obj] } }));
};
更新处理程序以使用要删除的 id
const deleteHoliday = (id) => {
const objects = state.daysOffList.filter((elm) => elm.id !== id);
setState(update(state, { daysOffList: { $set: objects } }));
};
使用元素 id 属性作为 React 键
{state.daysOffList?.map((elm, i) => {
return (
<Flex key={elm.id} gap="gap.small">
...
</Flex>
);
})}
将元素 id 传递给删除处理程序
<Button
primary
icon={<TrashCanIcon />}
text
onClick={() => deleteHoliday(elm.id)}
/>
使用 useEffect
React hook 记录任何状态更新
useEffect(() => {
console.log(state.daysOffList);
}, [state.daysOffList]);
注意:如果您不想(或不能)安装额外的 3rd-party 依赖项,那么您可以推出自己的 id 生成器。这将在紧要关头工作,但您真的应该寻求真正经过验证的解决方案。
const genId = ((seed = 0) => () => seed++)();
genId(); // 0
genId(); // 1