useEffect 中的 setTimeout 函数输出一个缓存的状态值
setTimeout function in useEffect outputs a cached state value
很简单。
我正在使用 Redux 来管理我的状态
我在 useEffect
函数中有一个 setTimeout
函数。
setTimeout
的超时值为 50000
毫秒。
我希望 SetTimeout 处理程序做什么
在 50000ms
之后,setTimeout
函数检查是否已收到 api 呼叫响应。
如果尚未收到响应,setTimeout
函数应重新发起 api 调用,因为那样调用将被视为超时。
回调处理程序在做什么
在 50000ms
之后,即使已收到响应,setTimeout 处理程序仍然会重新启动 api 调用。
我尝试记录状态的输出,然后它返回了缓存状态,即使状态已传递到 useEffect
函数的依赖数组并且应该已更新
调用api后,testDetails.isUpdatingTestDetails
状态设置为false
我尝试了几种逻辑,其中 none 有效
逻辑 1
useEffect(() => {
//Notice how i check if the testDetails is being updated before initiating the setTimeout callback
if (testDetails.isUpdatingTestDetails === true) {
setTimeout(() => {
// Inside the settimeout function the same check is also done.
// even though before 50 seconds the response is being received , the function logs the text simulating the reinitiation of an api call
return testDetails.isUpdatingTestDetails === true &&
console.log("After 50 Seconds You Need To Refetch This Data")
}, 50000);
}
}, [testDetails.isUpdatingTestDetails, testDetails])
逻辑 2
useEffect(() => {
setTimeout(() => {
return testDetails.isUpdatingTestDetails === true &&
console.log("After 50 Seconds You Need To Refetch This Data")
}, 50000);
}, [testDetails.isUpdatingTestDetails, testDetails])
None 我在上面应用的逻辑正在运行。
状态过时的原因:
useEffect
的回调形成了对当时状态的闭包。因此,当执行超时的回调时,它只能使用旧状态,即使状态同时更新也是如此。
一旦状态改变,useEffect
将再次运行(因为状态是依赖项)并开始新的超时。
第二次超时将使用新状态,因为闭包是用新状态形成的。如果状态第三次更改,此超时也容易受到陈旧状态问题的影响。
解法:
当状态改变时,您可以清除之前的超时。这样,除非是最新的,否则不会执行超时的回调。
export default function App() {
const [state, setState] = useState(true);
useEffect(() => {
const timeout = setTimeout(() => {
console.log(state);
}, 5000);
return () => {
// clears timeout before running the new effect
clearTimeout(timeout);
};
}, [state]);
return (
<div className="App">
<h1>State: {state.toString()}</h1>
<button onClick={() => setState(false)}>update</button>
</div>
);
}
const { useState, useEffect } = React;
function App() {
const [state, setState] = useState(true);
useEffect(() => {
const timeout = setTimeout(() => {
console.log(state);
}, 5000);
return () => {
// clears timeout before running the new effect
clearTimeout(timeout);
};
}, [state]);
return (
<div className="App">
<h1>State: {state.toString()}</h1>
<button onClick={() => setState(false)}>update</button>
</div>
);
}
ReactDOM.render(<App />, document.querySelector("#root"));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>
如果你想运行超时而不增加延迟的替代解决方案。如果延迟后状态发生变化,则不会启动新的超时。
您可以使用 useRef
挂钩随时引用最新状态。
这是一个例子。您可以修改以下内容以使用您的变量和逻辑。
export default function App() {
const [state, setState] = useState(true);
const stateRef = useRef(state);
// this effect doesn't need any dependencies
useEffect(() => {
const timeout = setTimeout(() => {
// use `stateRef.current` to read the latest state instead of `state`
console.log(stateRef.current);
}, 5000);
return () => {
// just to clear the timeout when component unmounts
clearTimeout(timeout);
};
}, []);
// this effect updates the ref when state changes
useEffect(() => {
stateRef.current = state;
}, [state]);
return (
<div className="App">
<h1>State: {state.toString()}</h1>
<button onClick={() => setState(false)}>update</button>
</div>
);
}
const { useState, useEffect, useRef } = React;
function App() {
const [state, setState] = useState(true);
const stateRef = useRef(state);
// this effect doesn't need any dependencies
useEffect(() => {
const timeout = setTimeout(() => {
// use `stateRef.current` to read the latest state instead of `state`
console.log(stateRef.current);
}, 5000);
return () => {
// just to clear the timeout when component unmounts
clearTimeout(timeout);
};
}, []);
// this effect updates the ref when state changes
useEffect(() => {
stateRef.current = state;
}, [state]);
return (
<div className="App">
<h1>State: {state.toString()}</h1>
<button onClick={() => setState(false)}>update</button>
</div>
);
}
ReactDOM.render(<App />, document.querySelector("#root"));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>
很简单。 我正在使用 Redux 来管理我的状态
我在 useEffect
函数中有一个 setTimeout
函数。
setTimeout
的超时值为 50000
毫秒。
我希望 SetTimeout 处理程序做什么
在 50000ms
之后,setTimeout
函数检查是否已收到 api 呼叫响应。
如果尚未收到响应,setTimeout
函数应重新发起 api 调用,因为那样调用将被视为超时。
回调处理程序在做什么
在 50000ms
之后,即使已收到响应,setTimeout 处理程序仍然会重新启动 api 调用。
我尝试记录状态的输出,然后它返回了缓存状态,即使状态已传递到 useEffect
函数的依赖数组并且应该已更新
调用api后,testDetails.isUpdatingTestDetails
状态设置为false
我尝试了几种逻辑,其中 none 有效
逻辑 1
useEffect(() => {
//Notice how i check if the testDetails is being updated before initiating the setTimeout callback
if (testDetails.isUpdatingTestDetails === true) {
setTimeout(() => {
// Inside the settimeout function the same check is also done.
// even though before 50 seconds the response is being received , the function logs the text simulating the reinitiation of an api call
return testDetails.isUpdatingTestDetails === true &&
console.log("After 50 Seconds You Need To Refetch This Data")
}, 50000);
}
}, [testDetails.isUpdatingTestDetails, testDetails])
逻辑 2
useEffect(() => {
setTimeout(() => {
return testDetails.isUpdatingTestDetails === true &&
console.log("After 50 Seconds You Need To Refetch This Data")
}, 50000);
}, [testDetails.isUpdatingTestDetails, testDetails])
None 我在上面应用的逻辑正在运行。
状态过时的原因:
useEffect
的回调形成了对当时状态的闭包。因此,当执行超时的回调时,它只能使用旧状态,即使状态同时更新也是如此。
一旦状态改变,useEffect
将再次运行(因为状态是依赖项)并开始新的超时。
第二次超时将使用新状态,因为闭包是用新状态形成的。如果状态第三次更改,此超时也容易受到陈旧状态问题的影响。
解法:
当状态改变时,您可以清除之前的超时。这样,除非是最新的,否则不会执行超时的回调。
export default function App() {
const [state, setState] = useState(true);
useEffect(() => {
const timeout = setTimeout(() => {
console.log(state);
}, 5000);
return () => {
// clears timeout before running the new effect
clearTimeout(timeout);
};
}, [state]);
return (
<div className="App">
<h1>State: {state.toString()}</h1>
<button onClick={() => setState(false)}>update</button>
</div>
);
}
const { useState, useEffect } = React;
function App() {
const [state, setState] = useState(true);
useEffect(() => {
const timeout = setTimeout(() => {
console.log(state);
}, 5000);
return () => {
// clears timeout before running the new effect
clearTimeout(timeout);
};
}, [state]);
return (
<div className="App">
<h1>State: {state.toString()}</h1>
<button onClick={() => setState(false)}>update</button>
</div>
);
}
ReactDOM.render(<App />, document.querySelector("#root"));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>
如果你想运行超时而不增加延迟的替代解决方案。如果延迟后状态发生变化,则不会启动新的超时。
您可以使用 useRef
挂钩随时引用最新状态。
这是一个例子。您可以修改以下内容以使用您的变量和逻辑。
export default function App() {
const [state, setState] = useState(true);
const stateRef = useRef(state);
// this effect doesn't need any dependencies
useEffect(() => {
const timeout = setTimeout(() => {
// use `stateRef.current` to read the latest state instead of `state`
console.log(stateRef.current);
}, 5000);
return () => {
// just to clear the timeout when component unmounts
clearTimeout(timeout);
};
}, []);
// this effect updates the ref when state changes
useEffect(() => {
stateRef.current = state;
}, [state]);
return (
<div className="App">
<h1>State: {state.toString()}</h1>
<button onClick={() => setState(false)}>update</button>
</div>
);
}
const { useState, useEffect, useRef } = React;
function App() {
const [state, setState] = useState(true);
const stateRef = useRef(state);
// this effect doesn't need any dependencies
useEffect(() => {
const timeout = setTimeout(() => {
// use `stateRef.current` to read the latest state instead of `state`
console.log(stateRef.current);
}, 5000);
return () => {
// just to clear the timeout when component unmounts
clearTimeout(timeout);
};
}, []);
// this effect updates the ref when state changes
useEffect(() => {
stateRef.current = state;
}, [state]);
return (
<div className="App">
<h1>State: {state.toString()}</h1>
<button onClick={() => setState(false)}>update</button>
</div>
);
}
ReactDOM.render(<App />, document.querySelector("#root"));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>