如何解决如何从 setTimeout 或 setInterval 回调访问 React 功能组件中的状态?
我无法通过 setInterval 或 setTimeout 回调访问 React 功能组件中的状态。
一个非常简单的示例,在一个时间间隔内更新状态并尝试使用绑定函数和未绑定箭头时间间隔回调访问状态。
https://codesandbox.io/s/pedantic-sinoussi-ycxin?file=/src/App.js
const IntervalExample = () => {
const [seconds,setSeconds] = useState(0);
useEffect(() => {
const interval1 = setInterval(() => {
setSeconds((seconds) => seconds + 1);
},1000);
const interval2 = setInterval(() => {
// this retrieves only the initial state value of 'seconds'
console.log("interval2: seconds elapsed",seconds);
},1000);
const interval3 = setInterval(function () {
// this retrieves only the initial state value of 'seconds'
console.log("interval3: seconds elapsed",1000);
return () => {
clearInterval(interval1);
clearInterval(interval2);
clearInterval(interval3);
};
},[]);
return (
<div className="App">
<header className="App-header">
{seconds} seconds have elapsed since mounting.
</header>
</div>
);
};
我希望在函数和箭头情况下都可以使用。任何帮助表示赞赏。
谢谢
解决方法
由于 stale closure,您在 setInterval 中看到 initial 状态值,您可以使用 setSeconds
(状态设置函数)作为解决方法修复过时的关闭问题:
const IntervalExample = () => {
const [seconds,setSeconds] = useState(0);
useEffect(() => {
const interval1 = setInterval(() => {
setSeconds((seconds) => seconds + 1);
},1000);
const interval2 = setInterval(() => {
let s = 0;
setSeconds((seconds) => {s = seconds; return seconds;}); // HERE
console.log("interval2: seconds elapsed",s);
},1000);
const interval3 = setInterval(function () {
let s = 0;
setSeconds((seconds) => {s = seconds; return seconds;}); // HERE
console.log("interval3: seconds elapsed",1000);
return () => {
clearInterval(interval1);
clearInterval(interval2);
clearInterval(interval3);
};
},[]);
return (
<div className="App">
<header className="App-header">
{seconds} seconds have elapsed since mounting.
</header>
</div>
);
};
如果您不需要在 UI 中显示 seconds
,您也可以使用 ref 变量。请注意,返回相同的值,即 seconds
函数中的 setSeconds
不会导致重新渲染。
我使用了 useStateAndRef 钩子,它适用于函数和箭头回调。
import "./styles.css";
import React,{ useState,useRef,useEffect } from "react";
function useStateAndRef(initial) {
const [value,setValue] = useState(initial);
const valueRef = useRef(value);
valueRef.current = value;
return [value,setValue,valueRef];
}
const IntervalExample = () => {
const [seconds,setSeconds,refSeconds] = useStateAndRef(0);
useEffect(() => {
console.log("useEffect[seconds] executing");
const interval1 = setInterval(() => {
setSeconds((seconds) => seconds + 1);
},1000);
const interval2 = setInterval(() => {
// this retrieves only the initial state value of 'seconds'
console.log("interval2: seconds elapsed",refSeconds.current);
},1000);
const interval3 = setInterval(function () {
// this retrieves only the initial state value of 'seconds'
console.log("interval3: seconds elapsed",[seconds]);
return (
<div className="App">
<header className="App-header">
{seconds} seconds have elapsed since mounting.
</header>
</div>
);
};
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<IntervalExample />
</div>
);
}
,
更新了 sandbox,在 useEffect
中没有依赖项
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。