【发布时间】:2021-04-07 05:31:01
【问题描述】:
抱歉标题令人困惑,但这是发生了什么:
在MyComponent 中,我使用useState React 挂钩设置count 状态。
一旦组件挂载(即useEffect 没有依赖项),我将实例化两个MyClass 对象,第一个参数作为增加状态的回调函数,第二个参数是timeOut 周期以调用回调功能。
MyClass 的第一个实例在 1000 毫秒内调用回调并为 count 设置新值,更新后将记录在第二个 useEffect 中。
但是,当MyClass 的第二个实例调用回调(在timeOut 3000 毫秒的周期之后)并尝试增加count 值时,它使用count 的状态,从@987654335 开始@ 已实例化(为 0),因此它将 count 递增到 1(想要的行为是递增到 2,因为 MyClass 的第一个实例已经将 count 从 0 递增到 1)
这不是与setState 的异步行为相关的问题,因为很明显,count 的第一次更新发生在第二个实例再次尝试更新它之前(第二个useEffect 在@987654342 时被调用@ 状态已更新,您可以从控制台日志消息中看到,这是在 MyClass 的第二个实例调用回调之前发生的。
JSFiddle 链接: https://jsfiddle.net/hfv24dpL/
总之,我认为问题在于回调函数中的count 状态是回调函数传递给MyClass 构造函数时count 状态的副本。
此示例的解决方案可能是仅在 count 状态更新时(在第二个 useEffect 中)实例化 MyClass 的第二个实例,但这不是我正在寻找的解决方案。
另一个解决方案是使用setCount(prevCount => prevCount + 1) 来增加count,但这在我的实际应用程序中不可行(MyComponent 和MyClass 是我为这个问题编写的真实 React 应用程序的骨架示例) .
我希望能够在组件挂载时一起实例化类(在第一个useEffect),并让回调引用count 的最新版本。
这个 ^ 是否有解决方案,或者没有办法绕过这个 javascript 和 React 实现?感谢您阅读所有这些,我知道它很长:)
import React, { useState, useEffect } from 'react';
class MyClass{
constructor(callback, timeOut){
// call callback in timeOut milliseconds
this.timeOutId = setTimeout(() => {
callback();
}, timeOut)
}
clearTimeOut(){
clearTimeout(this.timeOutId);
}
}
function MyComponent(){
var [count, setCount] = useState(0);
// component did mount
useEffect(() => {
let myClass1 = new MyClass(funcToCallback, 1000);
let myClass2 = new MyClass(funcToCallback, 3000);
// when component unmounts, clear the timeouts of MyClass instances
return () => {
myClass1.clearTimeOut();
myClass2.clearTimeOut();
}
}, []);
// counter state updated
useEffect(() => {
console.log("COUNT UPDATED TO: ", count);
}, [count])
// get counter and increment it by 1
function funcToCallback(){
console.log("CALLBACK CALLED");
let newCount = count + 1;
incCount(newCount);
}
function incCount(newCount){
console.log("NEW COUNT: ", newCount);
setCount(newCount);
}
return (
<div>
COUNT: { count }
</div>
)
}
【问题讨论】:
-
第一个问题很好!
标签: javascript reactjs react-state react-state-management