Javascript 为什么在异步函数中状态值只计算一次?
如果调用类似于Javascript 为什么在异步函数中状态值只计算一次?,javascript,reactjs,use-effect,Javascript,Reactjs,Use Effect,如果调用类似于setCount(count+1)的代码是非同步的,为什么count的值只计算一次? 当您按两次Async Naive递增计数按钮时,它会触发两次超时,一次延迟500毫秒,另一次延迟1000毫秒。因此,我认为由于第一次超时通过setCount(count+1)触发重新渲染,count的值应该在第二次超时中更新?因为500毫秒是执行操作的充足时间,重新渲染应该会导致在调用第二个超时函数时更新计数 如果将函数传递给setCount,则第二个按钮Increment Count tweep
setCount(count+1)
的代码是非同步的,为什么count的值只计算一次?当您按两次Async Naive递增计数按钮时,它会触发两次超时,一次延迟500毫秒,另一次延迟1000毫秒。因此,我认为由于第一次
超时
通过setCount(count+1)
触发重新渲染,count的值应该在第二次超时
中更新?因为500毫秒是执行操作的充足时间,重新渲染应该会导致在调用第二个超时
函数时更新计数
如果将函数传递给setCount
,则第二个按钮Increment Count tweep Async Robust
可以正常工作。所以如果count是1,它就变成了3。为什么在调用时评估的状态与前一个按钮不同
useffect(()=>{
如果(triggerAsyncIndex>1){
设置超时(()=>{
设置计数(计数+1);
}, 500);
}
},[triggerAsyncIndex]);
useffect(()=>{
如果(triggerAsyncIndex>1){
设置超时(()=>{
设置计数(计数+1);
}, 1000);
}
},[triggerAsyncIndex]);
useffect(()=>{
如果(triggerRobustAsyncIndex>1){
设置超时(
() =>
设置计数(上一个=>{
返回prev+1;
}),
500
);
}
},[triggerRobustAsyncIndex]);
useffect(()=>{
如果(triggerRobustAsyncIndex>1){
设置超时(
() =>
设置计数(上一个=>{
返回prev+1;
}),
1000
);
}
},[triggerRobustAsyncIndex]);
返回(
计数:{Count}
setCount(计数+1)}>增量计数
setTriggerAsyncIndex(triggerAsyncIndex+1)}>
增量计数两次异步初始化
setTriggerRobustAsyncIndex(triggerRobustAsyncIndex+1)}
>
两次递增计数异步健壮
);
}
功能组件中的状态更新不仅是异步的,而且是由闭包绑定的,如果使用setTimeout,它们仍然会引用定义函数的值,这并不重要
由于以下useEffect函数仅在triggerAsyncIndex
更改时重新触发,计数状态更新不会导致更新的值反映在第二个useEffect中,因为它在计数更新之前已经创建
useEffect(() => {
if (triggerAsyncIndex > 1) {
setTimeout(() => {
setCount(count + 1);
}, 500);
}
}, [triggerAsyncIndex]);
useEffect(() => {
if (triggerAsyncIndex > 1) {
setTimeout(() => {
setCount(count + 1);
}, 1000);
}
}, [triggerAsyncIndex]);
它需要重新呈现,以便在函数闭包中刷新计数值。旧的函数调用仍将保留以前的闭包值
这种情况下的想法是使用函数状态更新,如
setCount(prev=>prev+1)
函数组件中的状态更新不仅是异步的,而且是由闭包绑定的,如果使用setTimeout也无所谓,它们仍然会引用定义函数的值
由于以下useEffect函数仅在triggerAsyncIndex
更改时重新触发,计数状态更新不会导致更新的值反映在第二个useEffect中,因为它在计数更新之前已经创建
useEffect(() => {
if (triggerAsyncIndex > 1) {
setTimeout(() => {
setCount(count + 1);
}, 500);
}
}, [triggerAsyncIndex]);
useEffect(() => {
if (triggerAsyncIndex > 1) {
setTimeout(() => {
setCount(count + 1);
}, 1000);
}
}, [triggerAsyncIndex]);
它需要重新呈现,以便在函数闭包中刷新计数值。旧的函数调用仍将保留以前的闭包值
这种情况下的想法是使用函数状态更新,如
setCount(prev=>prev+1)
我明白了。因此,由于[triggerAsyncIndex]没有改变,第二个setTimeout触发器所在的环境(包括count的值)仍然是相同的。那么为什么传递(prev=>prev+1)会更新它,因为它不会触发重新渲染,因为[triggerAsyncIndex]未更改?这是因为react确保它在内部将更新的值传递给setState调用。这也不受闭包的影响,因为这些值是从函数回调参数而不是从封闭的作用域接收的。因此,您可以将react视为另一个内部闭包,它保存更新的状态并像(prev=>prev+1)使React有机会传递更新的值。因此,与每次关闭一样,它自己的腔室也被及时锁定。更改该腔室的唯一方法是重新创建(重新运行)它或访问包含当前文件室的更新文件室,对吗?除了您建议的两种方法之外,还有另一种方法。您可以在useEffect中将状态复制到ref,并且由于refs对变异有效,更新的值将在我看到的函数中看到。因此,由于[triggerAsyncIndex]没有更改,环境(包括count的值),其中第二个setTimeout触发器仍然是相同的。那么为什么passing(prev=>prev+1)会更新它,因为它不会触发重新呈现,因为[triggerAsyncIndex]未更改?这是因为react确保它在内部将更新的值传递给setState调用。这也不受闭包的影响,因为这些值是从函数回调参数而不是从封闭的作用域接收的。因此,您可以将react视为另一个内部闭包,它保存更新的状态并像(prev=>prev+1)使React有机会传递更新的值。因此,与每次关闭一样,它自己的腔室也被及时锁定。更改该腔室的唯一方法是重新创建(重新运行)它或访问包含当前文件室的更新文件室,对吗?除了您建议的两种方法之外,还有另一种方法。您可以在useEffect中将状态复制到ref,并且由于refs对变异有效,更新后的值将在函数中看到