我正在尝试使用react构建一个简单的树菜单。我发现this video确实显示了我想要实现的目标(his 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)
,在函数updateSelection中,绝对没有做任何事情(当然也不会触发useEffect)。
我不知道为什么。我在其上方放置了一个console.log,以检查变量(“ sel”)是否正确,但看起来还不错。我尝试对“ sel”的值进行硬编码,{chicken-id:{}},当我这样做时,它就可以工作。
答案 0 :(得分:0)
问题是您直接在改变状态对象:
if(selectedOptions[selectedOptionId]){
delete selectedOptions[selectedOptionId];
} else {
selectedOptions[selectedOptionId] = {}
}
onChange(selectedOptions);
在两种结果中,您都更改了状态对象,然后将其设置为自身,因此useEffect
自然不会触发,因为设置器未进行任何实际更改。您必须小心在React中执行此操作,因为这是结束陈旧值的简单方法。仅当当前状态与设置器传递的值之间存在差异时才触发重新渲染,而不是由于任何原因而在状态值发生更改时才触发重新渲染。
一条评论建议您使用传播-...
-分解状态对象,以便可以将其设置为自身,但这对我来说似乎有点反模式,尤其是当它离开状态时突变到位。如果要从状态对象中删除条目,则通常的方法是首先克隆对象,对克隆进行突变,然后将其设置为新状态:
const clone = Object.assign({}, selectedOptions);
if(clone[selectedOptionId]){
delete clone[selectedOptionId];
} else {
clone[selectedOptionId] = {}
};
onChange(clone);
不过请注意,该对象内的任何嵌套对象都将保留其对原始状态的引用,并且仍可能对其进行突变。您还必须克隆这些嵌套的对象,以避免出现此问题。