我有一个由3个复选框组成的组,和一个用于选中这3个复选框的主复选框。
有人可以向我解释幕后实际上发生了什么,并以某种方式帮助我解决React状态的这个奥秘吗?谢谢!
以下是代码片段:
state = {
data: [
{ checked: false, id: 1 },
{ checked: false, id: 2 },
{ checked: false, id: 3 }
],
main: false,
}
onCheckboxChange = id => {
const data = [...this.state.data];
data.forEach(item => {
if (item.id === id) {
item.checked = !item.checked;
}
})
const everyCheckBoxIsTrue = checkbox.every(item => item === true);
this.setState({ data: data, main: everyCheckBoxIsTrue });
}
onMainCheckBoxChange = () => {
let data = [...this.state.data];
data.forEach(item => {
!this.state.main ? item.checked = true : item.checked = false
})
this.setState({
this.state.main: !this.state.main,
this.state.data: data,
});
}
render () {
const checkbox = this.state.data.map(item => (
<input
type="checkbox"
checked={item.checked}
onChange={() => this.onCheckboxChange(item.id)}
/>
))
}
return (
<input type="checkbox" name="main" checked={this.state.main} onChange={this.onMainCheckBoxChange} />
{checkbox}
)
答案 0 :(得分:1)
我无法根据您提供的代码创建有效的代码段,其中一个问题是:
const everyCheckBoxIsTrue = checkbox.every(item => item === true);
未定义checkbox
的地方。
但是,我认为您对于使用旧状态还是新状态感到困惑,如果您清楚地命名,例如:
eventHandler() {
const { data } = this.state; // old state
const newData = data.map(each => ...); // new object, soon-to-be new state
this.setState({ data }); // update state
}
这是一个工作示例供您参考:
class App extends React.Component {
state = {
data: [
{ checked: false, id: 1 },
{ checked: false, id: 2 },
{ checked: false, id: 3 }
],
main: false,
}
onCheckboxChange(id) {
const { data } = this.state;
const newData = data.map(each => {
if (each.id === id) {
// Toggle the previous checked value
return Object.assign({}, each, { checked: !each.checked });
}
return each;
});
this.setState({
data: newData,
// Check if every checked box is checked
main: newData.every(item => item.checked === true),
});
}
onMainCheckBoxChange() {
const { main, data } = this.state;
// Toggle the previous main value
const newValue = !main;
this.setState({
data: data.map(each => Object.assign({}, each, { checked: newValue })),
main: newValue,
});
}
render () {
const { data, main } = this.state;
return (
<div>
<label>Main</label>
<input
type="checkbox"
name="main"
// TODO this should be automatically checked instead of assigning to the state
checked={main}
onChange={() => this.onMainCheckBoxChange()}
/>
{
data.map(item => (
<div>
<label>{item.id}</label>
<input
type="checkbox"
checked={item.checked}
onChange={() => this.onCheckboxChange(item.id)}
/>
</div>
))
}
</div>
);
}
}
ReactDOM.render(
<App />
, document.querySelector('#app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
旁注:您可能要考虑不使用
main
状态
答案 1 :(得分:0)
您不应该存储state.main
来确定是否选中了每个复选框。
您已经存储了确定是否选中所有复选框的状态,因为如果state.data
中的每个对象都具有checked: true
,则必须选中所有复选框。
您可以像这样简单地渲染主复选框:
<input
type="checkbox"
name="main"
checked={this.state.data.every(v => v.checked)}
onChange={this.onMainCheckBoxChange}
/>;
如果选中所有复选框,则this.state.data.every(v => v.checked)
行将返回true
。
并且当切换主复选框时,该函数可以如下所示:
onMainCheckBoxChange = () => {
this.setState(prev => {
// If all are checked, then we want to uncheck all checkboxes
if (this.state.data.every(v => v.checked)) {
return {
data: prev.data.map(v => ({ ...v, checked: false })),
};
}
// Else some checkboxes must be unchecked, so we check them all
return {
data: prev.data.map(v => ({ ...v, checked: true })),
};
});
};
优良作法是只存储需要存储的状态。可以从其他状态计算出的任何状态(例如,“是否都选中了所有复选框?”)应在render
函数内部进行计算。 See here说:
什么不应该进入州? ...计算数据:不必担心基于状态的预计算值-如果在render()中进行所有计算,则更容易确保UI一致。例如,如果您有一个处于状态的列表项数组,并且想要将计数呈现为字符串,则只需在render()方法中呈现this.state.listItems.length +'list items'而不是将其存储在状态中