案例1:
const [present, setPresent] = useState([]);
useEffect(() => {
for (var j = 1; j <= totalPeriod; j++) {
setPresent([
...present,
{
period: j,
present: true,
},
]);
}
}, []);
案例2:
const [present, setPresent] = useState([]);
let createPresent = [];
for (var j = 1; j <= totalPeriod; j++) {
createPresent = [
...createPresent,
{
period: j,
present: true,
},
]
}
useEffect(() => {
setPresent(createPresent);
}, []);
在案例1中,当我试图使用内部循环更新当前状态时,当前状态没有更新。但是,当我在用例2中单独使用useffect()之外的循环并创建一个数组,然后分配给当前状态时,当前状态正在更新。
这背后的原因是什么?为什么在案例1中当前状态没有更新?
除其他答案外:
在更新React组件中的状态时,需要记住一些关键点。首先,React状态中的更新状态是不同步的,因此将进行批处理,除非您异步触发它。
state = { count: 0};
increment() {
this.setState({ count: this.state.count + 1});
this.setState({ count: this.state.count + 1});
this.setState({ count: this.state.count + 1});
console.log(this.state.count) // 0
}
increment()
console.log(this.state.count); // 1
还有,这个的最终值。状态调用完成后,计数将为1
因为React批处理所有调用,并找出结果,然后有效地进行更改。有点像这种纯JavaScript代码,合并最后一个获胜的地方
newState = Object.assign(
{},
firstSetStateCall,
secondSetStateCall,
thirdSetStateCall,
);
所以,我们可以说这里的一切都与JavaScript对象合并有关。所以还有另一种很酷的方法,我们在setState中传递函数而不是对象。
其次,在react hooks的情况下,更新函数(useState()返回的数组的第二个元素)不会在state对象的内容更改时重新提交,必须更改state对象的引用。例如:这里我创建了沙盒:link
如果我没有更改数组的引用(即状态),它不会重新呈现组件。
for (let key in newState) {
newStateToBeSent[key] = newState[key]; // chnaging the reference
}
案例1中的假设是,setPresent调用是同步的,它会立即更新,而React中的状态更新实际上几乎总是异步的。因此,中存在变量(var j=1;j
[
...[],
{
period: j,
present: true,
},
]
这将导致您的状态更新到循环为创建的最后一个数组。因此,如果
totalPeriod
等于5,您的状态将最终为[{period:5,present:true}]
,而不是[{period:1,present:true},{period:2,present:true},…]
在案例2中,一切都非常简单,您可以在不干扰状态变量的情况下组装数组,然后一次性设置状态。就像你在这种情况下应该做的那样。
在以下情况下,您当前的状态不是每个后续状态更新的结果,而是您拥有的初始状态,即。React将批处理这些更新,并且不会使它们同步进行,因此只会有一个状态更新,并且更新到您的for循环中的最新条目。
const [present, setPresent] = useState([]);
useEffect(() => {
for (var j = 1; j <= totalPeriod; j++) {
setPresent([
...present,
{
period: j,
present: true,
},
]);
}
}, []);
在下面的例子中,您首先使用所需的所有值组装一个createPresent数组,最后调用状态更新程序函数,即setPresent来设置状态。
const [present, setPresent] = useState([]);
let createPresent = [];
for (var j = 1; j <= totalPeriod; j++) {
createPresent = [
...createPresent,
{
period: j,
present: true,
},
]
}
useEffect(() => {
setPresent(createPresent);
}, []);
为了使用first实现第二种行为,您可以使用状态更新器回调来保存前一个状态作为参数,如下所示:-
const [present, setPresent] = useState([]);
useEffect(() => {
for (let j = 1; j <= totalPeriod; j++) {
setPresent(prevState=>[
...prevState,
{
period: j,
present: true,
},
]);
}
}, []);
在这里,状态更新也是成批进行的,但在更新下一个状态之前,会将上一个状态考虑在内。
当我说批处理状态更新时,我的意思是只会有一个渲染。您可以通过在组件的函数体中执行console.log('渲染')
来验证这一点。
请注意,此处使用的是let而不是var,因为let的范围是有限的,所以您将获得变量j的准确值。
我试图更新包含我的复选框数据的对象数组。当用户单击复选框时,我需要更新值字段。我想我可以通过使用数组中的映射,然后使用扩展运算符来更新状态来实现这一点。 我的疑问是为什么使用查找方法时状态会更新?我以为只有设置方法可以更新状态。如果这是一个明显的错误,请提前道歉。 请检查更改输入功能。
我有一个对象的状态数组: 我有一个添加按钮,用于将对象添加到数组中,这是onclick事件的主体:
我目前正在构建一个动态表单引擎,希望在呈现应答摘要组件时显示redux存储区的结果。我认为最好的方法是在加载answerSummary组件后设置“complete”状态并将其设置为true,但在map函数中这样做不起作用,并抛出无限循环react错误。 代码如下: 编辑:我知道你不能在渲染中设置状态-我这样写是为了尝试和传达我想要做的事情
问题内容: 我一直在使用“ if”来测试自己的版本,并且一切似乎都正常。当然,如果使用signalAll()而不是signal(),这将导致严重崩溃,但是如果一次仅通知一个线程,这怎么会出错? 他们的代码在这里 -检查put()和take()方法;在Condition的JavaDoc顶部可以看到一个更简单,更重点的实现。 下面是我实施的相关部分。 PS我知道,通常,尤其是在这样的lib类中,应该让
问题内容: 我发现React Hooks文档的这两部分有些令人困惑。使用状态挂钩更新状态对象的最佳实践是哪一种? 想象一下要进行以下状态更新: 选项1 从使用React Hook的文章中,我们可以做到: 所以我可以做: 然后: 选项2 从钩子参考中我们可以得出: 与类组件中的setState方法不同,useState不会自动合并更新对象。您可以通过将函数更新程序形式与对象传播语法结合使用来复制此行
我发现这两个反应钩文档有点混乱。使用状态钩子更新状态对象的最佳实践是哪一个? 假设一个用户希望进行以下状态更新: 选择1 从使用React Hook一文中,我们可以看出这是可能的: 所以我可以做: 然后呢: 选择2 从Hooks参考中我们得到: 与类组件中的setState方法不同,useState不会自动合并更新对象。通过将函数更新程序窗体与对象扩展语法相结合,可以复制此行为: 据我所知,两者都