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

setInterval中useState值不更新:寻求非扩展/prev的持续更新方案

问题描述

在setInterval中尝试将持续变化的数据更新到useState Hook时,始终显示初始值。不想使用扩展运算符或prev构造(这类方法虽有效,但数据每秒更新一次会持续复制数据到内存,导致内存占用不断攀升),是否存在其他可持续更新useState值的方法?


编辑补充内容

数据结构

export const exData = {
  list: [] as deviceInfo[],
  add: function (newItem: deviceInfo) {
    this.list.push(newItem);
  },
  updateData: function (index: number, newValue: deviceInfo) {
    this.list[index] = newValue;
  },
  getData: function () {
    return this.list;
  },
};

export interface deviceInfo {
  ex1: any;
  ex2: any;
  ex3: any;
}

持续更新数据的代码(蓝牙低功耗设备扫描)

const handleDiscoverPeripheral = peripheral => {
    if (infoData === 'NewDevice') {
      exData.add({
        ex1,
        ex2,
        ex3,
      });
    } else if (infoData === 'UpdateDevice') {
      let indexDevices = findIndexList(exData.getData(), ex1);

      exData.updateData(indexDevices, {
        ex1,
        ex2,
        ex3,
      });
    }
};

更新FlatList的代码

const [getData, setData] = useState([]);

useEffect(() => {
  const interval = setInterval(() => {
     setData(exData.getData());
  }, 1000);

  return () => clearInterval(interval);
}, []);

useEffect(() => {
  console.log(getData);
}, [getData]);

解决方案

1. 直接在数据变更时触发重渲染(最优方案)

没必要用轮询,既然handleDiscoverPeripheral是数据变化的入口,直接在这里更新组件状态并触发重渲染,完全避免数组复制和轮询开销:

// 用一个空状态专门触发重渲染,不存储实际数据
const [, forceRender] = useState({});
// 用useRef保存最新数据引用,避免复制
const dataRef = useRef(exData.getData());

const handleDiscoverPeripheral = peripheral => {
    if (infoData === 'NewDevice') {
      exData.add({ ex1, ex2, ex3 });
    } else if (infoData === 'UpdateDevice') {
      const indexDevices = findIndexList(exData.getData(), ex1);
      exData.updateData(indexDevices, { ex1, ex2, ex3 });
    }
    // 更新最新数据引用
    dataRef.current = exData.getData();
    // 触发组件重渲染(空对象每次都是新引用,能触发更新)
    forceRender({});
};

// FlatList直接使用ref中的最新数据
<FlatList
  data={dataRef.current}
  // 其他属性...
/>

2. 优化轮询逻辑,仅在数据真的变化时更新

如果必须保留轮询逻辑,可以通过对比数据特征避免无效更新,同时用useRef追踪最新数据:

const [, forceRender] = useState({});
const dataRef = useRef(exData.getData());

useEffect(() => {
  const interval = setInterval(() => {
    const latestList = exData.getData();
    // 可根据实际场景调整对比逻辑,比如设备数量变化、唯一标识变更等
    if (dataRef.current.length !== latestList.length) {
      dataRef.current = latestList;
      forceRender({});
    }
  }, 1000);

  return () => clearInterval(interval);
}, []);

3. 给数据结构添加通知机制(适合长期维护)

修改exData,添加监听回调,当数据变更时主动通知组件更新,彻底摆脱轮询:

export const exData = {
  list: [] as deviceInfo[],
  listeners: [] as Function[],
  // 添加监听
  addListener(callback: Function) {
    this.listeners.push(callback);
  },
  // 移除监听
  removeListener(callback: Function) {
    this.listeners = this.listeners.filter(cb => cb !== callback);
  },
  // 通知所有监听者
  notifyListeners() {
    this.listeners.forEach(cb => cb());
  },
  add: function (newItem: deviceInfo) {
    this.list.push(newItem);
    this.notifyListeners();
  },
  updateData: function (index: number, newValue: deviceInfo) {
    this.list[index] = newValue;
    this.notifyListeners();
  },
  getData: function () {
    return this.list;
  },
};

组件中使用:

const [, forceRender] = useState({});
const dataRef = useRef(exData.getData());

useEffect(() => {
  const callback = () => {
    dataRef.current = exData.getData();
    forceRender({});
  };
  exData.addListener(callback);
  // 组件卸载时移除监听
  return () => exData.removeListener(callback);
}, []);

内容的提问来源于stack exchange,提问作者MertCelik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 00:53:11