钩子设置器不使用对象变量设置状态



我正在尝试用 react 构建一个简单的树形菜单。我发现这个视频准确地显示了我想要实现的目标(他的Codepen(。我能够实现他的方法,但后来出于好奇,试图使用钩子复制相同的方法。我最终得到了这个(简化(:

我的代码笔

const App2 = () => { 
const [selectedOptions, setSelectedOptions] = React.useState({});    
React.useEffect(() => {
console.log(selectedOptions);
},[selectedOptions]);
const updateSelection = (sel) => {
console.log(sel)
setSelectedOptions(sel);
}
return (
<div className="wrapper">
<h1>Toppings</h1>
<OptionsList 
options={options} 
onChange={updateSelection}
selectedOptions={selectedOptions} 
/>
</div>
);  
}
const OptionsList = ({ selectedOptions, onChange }) => { 
const handleCheckboxClicked = (selectedOptionId) => {   
if(selectedOptions[selectedOptionId]){
delete selectedOptions[selectedOptionId];
} else {
selectedOptions[selectedOptionId] = {}      
}    
onChange(selectedOptions);
}

return (
<div>
<button onClick={() => (handleCheckboxClicked("chicken-id"))} >
Set Chicken
</button>      
</div>
)
}
ReactDOM.render(<App2 />, document.querySelector('#app'));

问题是setSelectedOptions(sel),函数 updateSelect 内部绝对没有做任何事情(当然 useEffect 也没有被触发(。 我不知道为什么。我在它上面放了一个控制台.log以检查变量("sel"(是否正常,但似乎没问题。我尝试硬编码"sel"的值,{chicken-id:{}},当我这样做时它可以工作。

问题是你直接改变了状态对象:

if(selectedOptions[selectedOptionId]){
delete selectedOptions[selectedOptionId];
} else {
selectedOptions[selectedOptionId] = {}      
}    
onChange(selectedOptions);

在这两种结果中,您都更改了状态对象,然后将其设置为自身,因此自然不会触发useEffect,因为 setter 没有实际更改。在 React 中这样做时必须小心,因为这是一种以过时值结束的简单方法。仅当当前状态与资源库传递的值之间存在差异时,才会触发重新渲染,而不是在状态值出于任何原因更改时触发。

一条评论建议您使用 spread -...- 来解构状态对象,以便您可以将其设置为自身,但这对我来说似乎有点反模式,尤其是当它保留状态突变时。如果要从状态对象中删除条目,则一般方法是先克隆对象,更改克隆,然后将其设置为新状态:

const clone = Object.assign({}, selectedOptions);
if(clone[selectedOptionId]){
delete clone[selectedOptionId];
} else {
clone[selectedOptionId] = {}      
};
onChange(clone);

但需要注意的是,此对象中的任何嵌套对象都将保留其对原始状态的引用,并且仍可能使其发生变化。您还必须克隆这些嵌套对象以避免此问题。

相关内容

  • 没有找到相关文章

最新更新