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

如何在lodash filter中引用先前state解决定时器选值重复问题

问题根因

这是React Hooks典型的陈旧闭包问题:

  • 你当前的useEffect没有声明依赖,只会在组件首次挂载时执行一次,setInterval的回调函数从此就一直捕获着首次渲染时的panelRight初始值,永远拿不到后续更新后的状态。
  • 每次定时器触发时,过滤菜单用的panelRight都是同一个初始值,可选菜单池一直固定,自然会反复赋值同一个随机元素,逻辑不符合预期。
修复方法

优先用函数式更新的方案,不会打乱定时器的计时节奏,也不用额外处理依赖:

const [panelRight, setPanelRight] = useState(sample(filter(menu, (el) => el !== panelLeft)));

useEffect(() => {
  const interval = setInterval(() => {
    // 函数式setState的入参就是上一次更新后的最新状态,不存在闭包陈旧问题
    setPanelRight(prevRight => {
      const availableMenu = filter(menu, (el) => el !== panelLeft && el !== prevRight);
      return sample(availableMenu);
    });
  }, 10000);

  // 组件卸载时必须清除定时器,避免内存泄漏
  return () => clearInterval(interval);
}, [panelLeft]); // 如果panelLeft是动态变化的就保留在依赖里,是固定常量的话可以留空数组

如果你不想用函数式更新,也可以把所有响应式依赖加入useEffect的依赖数组,每次状态变化时重建定时器,保证回调捕获到最新值:

const [panelRight, setPanelRight] = useState(sample(filter(menu, (el) => el !== panelLeft)));

useEffect(() => {
  const interval = setInterval(() => {
    const availableMenu = filter(menu, (el) => el !== panelLeft && el !== panelRight);
    setPanelRight(sample(availableMenu));
  }, 10000);

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

这个方案的缺陷是每次panelRight更新都会重置10秒的计时周期,如果你的需求是严格每10秒切换一次,不受状态更新影响,就选第一种函数式更新的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 15:18:13