使用 useEffect 的清理功能可以非常轻松地取消请求
useEffect(() => {
let ignore = false;
fetchData(id).then(data => {
if (!ignore) {
setData(data);
}
});
return () => (ignore = true);
}, [id]);
我想做类似的事情,但我需要使用 useInterval 轮询数据
我想使用 fetchData(id)
轮询数据,如果请求已触发但 id
在响应解析之前发生了更改,则忽略返回的响应。
最佳答案
针对您的具体情况进行破解
假设您收到 id
作为 props 或类似的东西,这会起作用吗?
const Foo = ({ id }) => {
const [data, setData] = useState()
const passedId = useRef()
passedId.current = id
useInterval(() => {
fetchData(id)
.then(response => id === passedId.current && setData(response))
}, 5000)
// Render some JSX with the data
我在本地测试了与此非常相似的东西,基本上发生的事情是这样的:
Foo
接收id = 6
6
存储在passedId
中
useInterval
滴答声,我们请求id = 6
- 组件接收
id = 7
7
存储在passedId
中
id = 6
的请求已完成,但passedId.current === 7
因此未调用setData
id = 7
请求完成,id === PassedId.current
并调用setData
将类似的内容放入useInterval
注意 - 未经测试
也许取消效果如此简单的原因是因为该函数返回自己的清理,因此 ignore
不必在外部范围内。但 setInterval
不允许返回值。我们也许可以使用setTimeout
来解决这个问题:
function useInterval(callback, delay) {
useEffect(() => {
let cleanup
let id
function tick() {
cleanup = callback()
id = setTimeout(tick, delay)
}
if (delay !== null) {
tick()
return () => {
clearTimeout(id)
cleanup && cleanup()
}
}
return () => cleanup && cleanup()
}, [callback, delay])
其中的一个问题是,现在我们在依赖项数组中有 callback
,因此应该使用 useCallback
创建给 useInterval
的回调:
const Foo = ({ id }) => {
const [data, setData] = useState()
const pollData = useCallback(() => {
let shouldUpdate = true
fetchData(id).then(resp => shouldUpdate && setData(resp))
return () => shouldUpdate = false
}, [id])
useInterval(pollData, 5000)
// Render some JSX with the data
- 当调用
useInterval
时,我们设置一个useEffect
来执行callback
- 当
callback
执行时,返回值(它的清理)被存储在cleanup
中,它的作用域是effect和一个setTimeout
设置为在延迟
毫秒 后重新执行
- 如果
callback
发生变化(即我们获得新的id
),那么我们会清除超时并为之前的回调运行清理 delay
毫秒后,再次执行tick
关于javascript - 使用 useInterval 钩子(Hook)取消异步请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58258713/