React中使用useState、useEffect、useCallback实现间隔请求并正确配置依赖
问题原因
两个异常表现的核心逻辑如下:
console.log无输出:fetchAllCameras是异步函数,调用后不会等待接口请求完成就会立即执行后续的if(allCameras)判断,此时setAllCameras尚未执行;就算后续请求完成更新了state,当前_fetchData函数作用域内捕获的allCameras依然是初始旧值,无法触发打印逻辑。- 加
allCameras依赖触发无限循环:allCameras更新后会导致_fetchData的useCallback重新生成新的函数引用,进而触发外层useEffect重新执行,再次调用_fetchData、请求接口、更新allCameras,形成死循环。
解决方案
方案1:拆分数据处理逻辑
不需要把allCameras加入_fetchData的依赖,把对allCameras的处理逻辑拆分到接口请求回调或者单独的useEffect中即可:
const [allCameras, setAllCameras] = useState() const fetchAllCameras = useCallback(async () => { try { const res = await getAllCameras(); if(res.data.status_code === 0 && res.data.data){ const newCameras = res.data.data setAllCameras(newCameras) // 直接在请求回调中处理最新拿到的摄像头数据 console.log("allCameras", newCameras) } } catch (err) { console.error(err); } }, []) const _fetchData = useCallback(async () => { fetchAllCameras() }, [fetchAllCameras]) useEffect(() => { _fetchData(); const intervalID = setInterval(() => { _fetchData(); }, FETCH_INTERVAL * 1000); return () => clearInterval(intervalID); }, [_fetchData]); // 如果需要在state更新后执行其他业务逻辑,单独加useEffect监听即可 useEffect(() => { if(!allCameras) return console.log("allCameras更新后触发:", allCameras) }, [allCameras])
方案2:用ref同步state值
如果确实需要在_fetchData中读取最新的allCameras值,可以用ref同步state,避免将state加入依赖触发循环:
const [allCameras, setAllCameras] = useState() // 新增ref同步state的最新值 const camerasRef = useRef(allCameras) useEffect(() => { camerasRef.current = allCameras }, [allCameras]) const fetchAllCameras = useCallback(async () => { try { const res = await getAllCameras(); if(res.data.status_code === 0 && res.data.data){ setAllCameras(res.data.data) } } catch (err) { console.error(err); } }, []) const _fetchData = useCallback(async () => { fetchAllCameras() // 从ref读取最新值,不需要把allCameras加入依赖 if(camerasRef.current){ console.log("allCameras", camerasRef.current) } }, [fetchAllCameras]) useEffect(() => { _fetchData(); const intervalID = setInterval(() => { _fetchData(); }, FETCH_INTERVAL * 1000); return () => clearInterval(intervalID); }, [_fetchData]);
内容的提问来源于stack exchange,提问作者Shreyas Chorge
相关产品推荐
相关产品推荐

