在调用setInterval
函数之前,我已将状态设置为true。但是,即使useEffect
钩子是由状态的新值触发的,也没有反映在setInterval
函数中。
此处的代码沙箱:https://jsfiddle.net/6e05tc2L/3/
let interval;
const Component = () => {
React.useEffect(() => {
console.log('State updated to', state);
});
const [state, setState] = React.useState(false);
const on = () => {
setState(true);
interval = setInterval(() => {
console.log(state);
}, 1000);
}
const off = () => {
setState(false);
clearInterval(interval);
}
const toggle = () => state ? off() : on()
return (<div>
<button onClick={toggle}>Toggle State</button>
</div>);
}
ReactDOM.render(
<Component />,
document.getElementById('container')
);
一旦更新,就不应该使用新的state值吗?
答案 0 :(得分:3)
传递给useEffect的函数内部的值在每个渲染器上都会刷新,因为useEffect使用了传递给它的函数的新定义。
但是传递给setInterval的函数只定义了一次,它关闭了状态的旧值。尚未更新。
使用钩子进行闭包是很棘手的,但是要意识到的是useEffect为每个渲染创建了一个新函数,因此每次函数关闭一个新的状态值时都会创建一个新函数。
然后,诀窍是在useEffect自身内部调用与setInterval相关的代码,该函数本身取决于state的变化值
React.useEffect(() => {
if(state) {
interval = setInterval(() => {
console.log(state);
}, 1000);
} else {
clearInterval(interval);
}
}, [state]);
或者更好的是,使用useInterval挂钩为您处理这些详细信息。
答案 1 :(得分:1)
setInterval
始终可以访问组件的 first 呈现器的值,因为传递给setInterval
的函数会围绕该值闭合,并且不会被重新声明。您可以使用自定义钩子解决此问题:
function useInterval(callback, delay) {
const savedCallback = useRef();
useEffect(() => {
savedCallback.current = callback;
});
useEffect(() => {
function tick() {
savedCallback.current();
}
let id = setInterval(tick, delay);
return () => clearInterval(id);
}, [delay]);
}
该实现和对React Hooks与setInterval
之间不匹配的详尽解释是来自React贡献者之一的丹·阿布拉莫夫Making setInterval Declarative with React Hooks。
答案 2 :(得分:0)
如果您希望在状态更改时重新加载组件,则应像这样创建useEffect。
Array (
[mode] => isu
[merchantId] => DEMOPAYPAL
[merchantIdInPayPal] => ***********
[permissionsGranted] => true
[consentStatus] => true
[productIntentId] => addipmt
[isEmailConfirmed] => true
[accountStatus] => BUSINESS_ACCOUNT
)
您创建的方式与React.useEffect(() => {
console.log('State updated to', state);
}, [state]);
相同,只是将数组作为第二个参数,就像componentDidMount()
一样,它具有依赖性。因此,只要您的状态发生变化,您的组件就会重新呈现。
要解决setTimeout的无穷大调用,您可以在创建函数的地方进行
componentDidUpdate()
使用此React会知道您只想创建一次此功能。
答案 3 :(得分:0)
我不是ReactJS专家,但是我猜您正在记录的React.useCallback(() => {
setInterval(() => {
console.log(state);
}, 1000);
})
不会刷新,因为它被声明一次且从未刷新过。如果state
是为您提供状态的方法,则应在间隔函数中使用它。
以下是我要解释的示例:
React.useState(false)