我有这段代码,我的问题是为什么在我的答案函数中会得到initialState。如何以适当的方式设置状态以在setTimeout函数的回调中获取正确的状态?
const App = () => {
const [state, setState] = useState({
name: "",
password: "",
});
useEffect(() => {
setState({ ...state, password: "hello" });
setTimeout(answer, 1000);
}, []);
const answer = () => {
console.log(state);
// we get initial State
};
return <div className="App"></div>;
};
答案 0 :(得分:2)
原因是关闭。
answer
函数将始终记录state
函数在被调用时关闭的setTimeout()
的值。
在您的代码中,由于setTimeout()
包含一个具有空值的对象时将调用state
函数,因此answer
函数将记录该值,而不是记录更新的值。
要记录状态的最新值,可以使用useRef()挂钩。该挂钩返回一个对象,该对象包含名为current
的属性,该属性的值是传递给useRef()
的参数。
function App() {
const [state, setState] = React.useState({
name: "",
password: "",
});
const stateRef = React.useRef(state);
React.useEffect(() => {
stateRef.current = { ...stateRef.current, password: 'hello'};
setState(stateRef.current);
setTimeout(answer, 1000);
}, []);
const answer = () => {
console.log(stateRef.current);
};
return <div></div>;
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
答案 1 :(得分:0)
函数answer
是除state值之外的闭包,它在定义时在其作用域内捕获变量的值。调用useEffect内部的回调时,其获取的答案方法将关闭setState之前的状态值。
这就是您将与之通话的函数setTimeout
,因此,即使有超时,状态的旧值也会被延迟。