反应复选框。切换复选框时状态迟到
Posted
技术标签:
【中文标题】反应复选框。切换复选框时状态迟到【英文标题】:React checkboxes. State is late when toggling the checkboxes 【发布时间】:2020-08-07 11:07:00 【问题描述】:我有一组 3 个复选框和用于检查这 3 个复选框的主复选框。
当我选中所有 3 个复选框时,我希望 main 复选框被选中。 当我选中这 3 个复选框时,没有任何反应,但是当我取消选中其中一棵树时,main 复选框变为选中状态。有人可以向我解释幕后实际发生的事情并帮助我以某种方式解决这个 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
)
【问题讨论】:
【参考方案1】:我无法根据您提供的代码制作工作代码 sn-p,其中一个问题是:
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
状态
【讨论】:
非常感谢。我还有一个问题。为什么要用括号括起来 data 变量? // 常量 data = this.state @Rakonjac 不用担心!啊,这是对象解构,所以const data = this.state;
与const data = this.state.data;
相同,因为this.state
是一个对象。如果您想从同一个对象访问多个,这很有用,例如:const data, main = this.state;
而不是const data = this.state.data; const main = this.state.main;
,因为每次调用this.state.xxx
,您的程序都会访问内存,因此在这种情况下使用解构将最小化(也更容易阅读代码)。我建议你使用 ESLint 来学习好的实践:)
听起来不错。再次感谢,您的解释很有帮助。【参考方案2】:
您不应该存储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' 而不是将其存储在状态中.
【讨论】:
以上是关于反应复选框。切换复选框时状态迟到的主要内容,如果未能解决你的问题,请参考以下文章