You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 08:24:02