【发布时间】:2021-03-30 08:14:55
【问题描述】:
所以我在测试时发现了一个非常奇怪的 React useState 行为,无法真正解释原因。
所以下面是我的代码。我正在创建一个带有复选框的 React ListItem。由于用户可以选择多个复选框,所以我觉得最好使用数组存储活动索引。并使用 array.includes 函数检查某个索引是否处于活动状态。当我这样做时,我发现数组 useState 没有立即更新,所以我的复选框检查不起作用。但是,我添加了一个如下所示的随机激活器,突然数组及时更新,我的代码开始工作。我希望我的问题很清楚。有人可以解释为什么会这样吗?
我做了更多的测试,发现激活器需要传入索引变量。如果我传入一些随机值会导致不一致的行为
const [activeIndex, setactiveIndex] = useState([]);
const [_, activator] = useState(-1); //If I add this line of code the array gets updated in time
const ModifyActiveIndex = (index) => {
activator(index);
if (!activeIndex.includes(index)) {
const copy = activeIndex;
copy.push(index);
setactiveIndex(copy);
} else {
const filtercopy = activeIndex.filter((item) => {
return item !== index;
});
setactiveIndex(filtercopy);
}
};
const checkEntityactive = (index) => {
return activeIndex.includes(index);
};
const ProductList = temp.map((element, index) => {
return (
<ListItem key={index}>
<Checkbox
checked={checkEntityactive(index)}
onClick={() => ModifyActiveIndex(index)}
/>
</ListItem>
);
});
【问题讨论】:
-
const copy = activeIndex;不会创建副本,它本质上只是将activeIndex重命名为copy,数组仍然是相同的引用,所以当你使用@ 时你正在改变你的状态987654325@。您也不需要在执行过滤器时创建copy变量,因为过滤器方法将为您创建一个新数组 -
是的,我只是在测试期间添加的那行代码。我可以拿出来。但这并不能解决问题
-
我猜如果你把它拿出来,那么你可能正在做类似
activeIndex.push(index)的事情?如果是这样,那么如果您这样做,您仍然会直接修改状态。您需要创建一个新数组,并将新索引添加到该setactiveIndex([...activeIndex, index]) -
是的,我的代码仍然可以工作的唯一方法是添加 activator(index) 行。所有其他更改都可以使代码更简单,但不能解决问题。我只想知道为什么那行代码解决了我的问题
-
代码执行到
copy.push(index);时,状态已经改变,但setactiveIndex(copy)的参数是数组引用,所以直到activator(index);才会重新渲染组件。activator(index);将在copy.push(index);之后执行,因为 setState 在事件处理程序中是异步的。实际上,如果你删除setactiveIndex(copy);。它仍然有效。