我相信您遇到的问题是因为您没有正确分离每个组件的关注点,一旦您每次都必须中继以前的数据,useEffect 可能会很棘手。但是您的问题有两种解决方案:
利用useState回调函数:
useState 函数可以与回调而不是值一起使用,如下所示:
useEffect(() => {
if (isSelected) {
setMyState(prevState => [
...prevState,
{
propOne: 0,
propTwo: 1,
id: item.id,
...
},
])
} else {
setMyState(result)
}
}, [isSelected])
组件的最佳结构 + 使用 useState 回调函数
我可以看到您的方法是您(如您所展示的)似乎正在尝试处理每个项目的isSelected 和同一组件中的myState,这可以完成,但这并不理想。所以我建议创建两个组件,比如说:
-
<List />:应该处理回调以选择一个项目并渲染它们。
<List />:
function List() {
const [myState, setMyState] = useState([]);
const isItemSelected = useCallback(
(itemId) => myState.some((el) => el.id === itemId),
[myState]
);
const handleSelectItem = useCallback(
(itemId) => {
const isSelected = isItemSelected(itemId);
if (isSelected) {
setMyState((prevState) => prevState.filter((el) => el.id !== itemId));
} else {
setMyState((prevState) => prevState.concat({ id: itemId }));
}
},
[isItemSelected]
);
return (
<div>
<p>{renderTimes ?? 0}</p>
{items.map((item) => (
<Item
item={item}
onSelectItem={handleSelectItem}
selected={isItemSelected(item.id)}
/>
))}
</div>
);
}
-
<Item />:应在内部处理每个项目的 isSelected 字段。
<Item />:
const Item = ({ item, selected = false, onSelectItem }) => {
const [isSelected, setIsSelected] = useState(false);
useEffect(() => {
setIsSelected(selected);
}, [selected]);
return (
<div>
<p>
{item.name} is {isSelected ? "selected" : "not selected"}
</p>
<button onClick={() => onClick(item.id)}>
{isSelected ? "Remove" : "Select"} this item
</button>
</div>
);
};
这是codesnack,我在其中添加了一个计算渲染的函数,因此您可以检查解决方案的性能。