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

React异步函数中state判断失效 curstep状态无法按条件更新如何解决?

问题原因

你遇到的是典型的React闭包陷阱问题:

  • 用来启动定时器的useEffect依赖项为空,只会在组件首次挂载时执行一次
  • 此时创建的setInterval回调以及内部调用的detect函数,捕获的curstep永远是首次渲染时的初始值0
  • 后续调用setCurstep更新状态只会触发组件重渲染,不会更新已经创建的闭包里的curstep值,所以curstep === 1、curstep === 2的判断永远无法命中,去掉判断直接更新状态自然是正常的。

解决方案

有三种常用的方法可以规避这个问题:

方案1:使用状态的函数式更新(最推荐,改动最小)

setCurstep支持传入函数作为参数,函数的入参永远是最新的当前状态值,不需要依赖闭包捕获的变量:

const [curstep, setCurstep] = useState(0);
const detect = async (net) => {
  const hand = await net.estimateHands(video);
  const gesture = await net.estimate(hand[0].landmarks, 4);
  setCurstep(prevStep => {
    if (prevStep === 0 && gesture === "Number 1") return 1;
    if (prevStep === 1 && gesture === "Number 2") return 2;
    if (prevStep === 2 && gesture === "Number 3") return 3;
    // 不满足条件时返回原有值,不触发状态更新
    return prevStep;
  })
}

useEffect(() => {
  let timer = null;
  const runHandpose = async () => {
    const net = await handpose.load();
    timer = setInterval(() => {detect(net)}, 30);
  }
  runHandpose();
  // 组件卸载时清除定时器,避免内存泄漏
  return () => clearInterval(timer);
}, []);

方案2:用useRef同步最新状态值

用ref存储最新的curstep,ref的current值是可变的,不会被闭包捕获:

const [curstep, setCurstep] = useState(0);
// 创建ref同步状态
const curstepRef = useRef(curstep);
// 状态更新时同步到ref
useEffect(() => {
  curstepRef.current = curstep;
}, [curstep]);

const detect = async (net) => {
  const hand = await net.estimateHands(video);
  const gesture = await net.estimate(hand[0].landmarks, 4);
  // 读取ref的current值,永远是最新的
  if (curstepRef.current === 0 && gesture === "Number 1")
    setCurstep(1);
  else if (curstepRef.current === 1 && gesture === "Number 2")
    setCurstep(2);
  else if (curstepRef.current === 2 && gesture === "Number 3")
    setCurstep(3);
}

// 定时器逻辑和方案1一致

方案3:给useEffect添加curstep依赖

把curstep加入useEffect的依赖数组,每次curstep变化时重新创建定时器,注意要在清理函数中销毁旧的定时器,避免重复创建多个定时器:

const [curstep, setCurstep] = useState(0);
const detect = async (net) => {
  const hand = await net.estimateHands(video);
  const gesture = await net.estimate(hand[0].landmarks, 4);
  if (curstep === 0 && gesture === "Number 1")
    setCurstep(1);
  else if (curstep === 1 && gesture === "Number 2")
    setCurstep(2);
  else if (curstep === 2 && gesture === "Number 3")
    setCurstep(3);
}

useEffect(() => {
  let timer = null;
  const runHandpose = async () => {
    // 建议把加载好的net用useRef存起来,避免每次curstep变化都重复加载模型
    const net = await handpose.load();
    timer = setInterval(() => {detect(net)}, 30);
  }
  runHandpose();
  // 每次依赖变化、组件卸载时清除旧定时器
  return () => clearInterval(timer);
}, [curstep]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 19:06:01