React - useState - 为什么 setTimeout 函数没有最新的状态值? [英] React - useState - why setTimeout function does not have latest state value?
问题描述
最近我在研究 React Hooks,但遇到了一个问题/疑问?
下面是重现问题的基本实现,这里我只是在单击按钮时切换 flag
(状态)变量.
const [flag, toggleFlag] = useState(false);const 数据 = useRef(null);data.current = 标志;const _onClick = () =>{toggleFlag(!flag);//toggleFlag(!data.current);//在职的setTimeout(() => {toggleFlag(!flag);//没有最新值,为什么?//toggleFlag(!data.current);//在职的}, 2000);};返回 (<div className="应用程序"><button onClick={_onClick}>{flag ?"true" : "false"}</button>
);
我想出了一些其他方法来解决这个问题,比如使用 useRef 或 useReducer,但这是正确的还是有其他方法可以仅使用 useState 来解决这个问题?
此外,如果有人解释为什么我们在 setTimeout 中获得旧的状态值,那将非常有帮助.
沙盒网址 - https://codesandbox.io/s/xp540ynomo
这归结为闭包在 JavaScript 中的工作原理.赋予 setTimeout
的函数将从初始渲染中获取 flag
变量,因为 flag
未发生变异.
您可以改为提供一个函数作为 toggleFlag
的参数.此函数将获取正确的 flag
值作为参数,此函数返回的内容将替换状态.
示例
const { useState } = React;功能应用(){const [标志,toggleFlag] = useState(false);const _onClick = () =>{toggleFlag(!flag);setTimeout(() => {toggleFlag(flag => !flag)}, 2000);};返回 (<div className="应用程序"><button onClick={_onClick}>{flag ?"true" : "false"}</button>
);}ReactDOM.render(
<script src="https://unpkg.com/react@16/umd/react.development.js"><;/脚本><script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script><div id="root"></div>
Recently I was working on React Hooks and got stuck with one problem/doubt?
Below is a basic implementation to reproduce the issue, Here I'm just toggling flag
(a state) variable on click of the button.
const [flag, toggleFlag] = useState(false);
const data = useRef(null);
data.current = flag;
const _onClick = () => {
toggleFlag(!flag);
// toggleFlag(!data.current); // working
setTimeout(() => {
toggleFlag(!flag); // does not have latest value, why ?
// toggleFlag(!data.current); // working
}, 2000);
};
return (
<div className="App">
<button onClick={_onClick}>{flag ? "true" : "false"}</button>
</div>
);
I figured out some other way to overcome this problem like using useRef or useReducer, but is this correct or is there any other way to solve this with useState only?
Also, it would be really helpful if anyone explains why we get old value of state inside the setTimeout.
Sandbox URL - https://codesandbox.io/s/xp540ynomo
This boils down to how closures work in JavaScript. The function given to setTimeout
will get the flag
variable from the initial render, since flag
is not mutated.
You could instead give a function as argument to toggleFlag
. This function will get the correct flag
value as argument, and what is returned from this function is what will replace the state.
Example
const { useState } = React;
function App() {
const [flag, toggleFlag] = useState(false);
const _onClick = () => {
toggleFlag(!flag);
setTimeout(() => {
toggleFlag(flag => !flag)
}, 2000);
};
return (
<div className="App">
<button onClick={_onClick}>{flag ? "true" : "false"}</button>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
这篇关于React - useState - 为什么 setTimeout 函数没有最新的状态值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!