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

交通信号灯动态计时器问题:减少秒数时信号流转异常

解决路口信号灯动态调整秒数后流转异常的问题

你的问题核心在于未清理旧定时器和状态闭包导致的旧值引用,加上useEffect依赖项设置不当:当减少秒数时,之前设置的长周期定时器仍在运行,和新的短周期定时器同时触发,直接打乱了信号灯的流转顺序。

以下是具体解决方案:

1. 给useEffect添加定时器清理逻辑

每次组件重新渲染(包括秒数变化)时,必须清除上一次的定时器,避免旧定时器继续执行干扰新时序。

2. 修正useEffect依赖项与状态更新逻辑

将signal和sec作为依赖项传入useEffect,确保状态变化时重新创建定时器;同时使用函数式更新获取最新的signal状态,彻底解决闭包导致的旧值引用问题。

3. 处理秒数类型与边界校验

TextInput的value是字符串类型,需转成数字并做边界校验(确保秒数≥1),避免NaN或无效值导致的定时器异常。

修改后的完整核心代码

const signalOrder = ['signalOne', 'signalTwo', 'signalThree', 'signalFour'];

const [signal, setSignal] = useState(signalOrder[0]);
const [visible, setVisible] = useState(true);
const [seconds, setSeconds] = useState('2');
const [sec, setSec] = useState(2); // 改为数字类型,避免重复转换

useEffect(() => {
  // 秒数小于1时不启动定时器,避免异常
  if (sec < 1) return;
  
  const timer = setTimeout(() => {
    setSignal(prevSignal => {
      const index = signalOrder.indexOf(prevSignal);
      // 简化索引计算:取模实现循环切换
      const nextIndex = (index + 1) % signalOrder.length;
      return signalOrder[nextIndex];
    });
  }, sec * 1000);

  // 清理函数:组件卸载或依赖变化时清除定时器
  return () => clearTimeout(timer);
}, [signal, sec]); // 依赖项:signal变化时切换下一个,sec变化时重新计时

const changeTime = () => {
  // 转成数字并做边界校验,确保至少为1
  const newSec = Math.max(1, parseInt(seconds, 10) || 1);
  setSec(newSec);
  setVisible(true);
};

UI部分的小优化(可选)

给TextInput添加输入过滤,只允许正整数输入:

<TextInput
  style={styles.textInput}
  value={seconds}
  onChangeText={second => {
    // 过滤非数字字符,只保留正整数
    const numOnly = second.replace(/[^0-9]/g, '');
    setSeconds(numOnly);
  }}
  keyboardType="number-pad"
/>

方案说明

  • 定时器清理:每次useEffect执行前清除旧定时器,确保同一时间只有一个定时器在运行,彻底避免多定时器冲突。
  • 函数式状态更新:setSignal(prevSignal => ...)直接获取最新的信号灯状态,解决闭包导致的旧值引用问题,保证切换逻辑始终基于当前状态。
  • 类型与边界校验:避免非数字输入导致的定时器异常,同时确保秒数有效,防止定时器设置为0或负数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 10:02:39