我无法从回调中访问组件状态。
状态值num
正确更改,但此类更改对加载时定义的回调函数不可见。
import React, {useState} from "react";
class MyObject {
callback: (() => void);
constructor(callback: () => void) {
this.callback = callback;
}
};
export const TestPage = () => {
const [num, setNum] = useState<number>(0);
// will print the changing values
console.log(`num: ${num}`);
const counter = useState<MyObject>(() => new MyObject(() => {
// will always print 0
console.log(`from callback. num: ${num}`);
}))[0];
const btnClick = () => {
setNum((new Date()).getTime());
counter.callback();
};
return (
<div>Test, num: {num}
<div>
<button onClick={btnClick}>click to update state</button>
</div>
</div>
);
}
普通的非 React 代码不会发生上述情况,如下所示
let myVar = 0;
const obj = new MyObject(() => console.log(`myVar: ${myVar}`));
obj.callback(); // prints 0
myVar = 1;
obj.callback(); // prints 1
编辑:我试图重现闭包的问题,但我不能
const makeFun = (callback: (() => void)) => {
return () => {
callback();
}
}
let myVar = 0;
const f1 = makeFun(() => console.log(`myVar: ${myVar}`));
myVar = 1;
const f2 = makeFun(() => console.log(`myVar: ${myVar}`));
f1(); // prints 1
f2(); // prints 1
所以我怀疑是特定于 React 和 useState 的。
有任何想法吗?
编辑#2:解决方案。这是如何使它在非 React 代码中可见。
let callbackPersistent: (() => void);
const createCallback = (callback: (() => void)) => {
if (!callbackPersistent) {
callbackPersistent = callback;
}
return callbackPersistent;
}
const myFunction = (num:number) => {
const callback = createCallback(() => console.log(`callback num: ${num}`));
callback();
};
然后将其称为
myFunction(0); // prints 0
myFunction(1); // prints 0
只有一个回调实例,它指向它第一次创建时看到的值。
编辑#3:
useRef
使用and可以找到一个合理的解决方案useEffect
,如下所示:
import React, {useEffect, useRef, useState} from "react";
class MyObject {
callback: (() => void);
constructor(callback: () => void) {
this.callback = callback;
}
};
export const TestPage = () => {
const [num, setNum] = useState<number>(0);
const numRef = useRef(num);
// will print the changing values
console.log(`num: ${num}`);
const counter = useState<MyObject>(() => new MyObject(() => {
// will always print the latest value
console.log(`from callback. num: ${numRef.current}`);
}))[0];
useEffect(()=> {numRef.current = num}, [num]);
const btnClick = () => {
setNum(new Date().getTime());
counter.callback();
};
return (
<div>Test, num: {num}
<div>
<button onClick={btnClick}>click to update state</button>
</div>
</div>
);
}
useRef
保证numRef
在多次调用中始终是同一个对象。当值num
更改时,onEffect
调用将更新numRef.current
值,然后由回调访问。只有一个回调实例和numRef
存在,确保正确拾取更改