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

React Native Expo中unstable_pressDelay未完全生效问题排查

问题分析

你的反应时间测试界面存在以下核心问题:

  • 用全局变量c控制界面颜色状态,和React的count状态不同步,导致流程逻辑混乱。
  • 没有状态锁机制,用户在测试流程中重复按压会触发新的start函数,跳过原有流程。
  • 固定1秒延迟而非随机时长,且未清理定时器,多个定时器叠加导致状态异常。
  • unstable_pressDelay无法阻止重复触发pressIn,该参数仅用于延迟Pressable的"press"状态激活,不是防止事件重复调用。
解决方案

重构代码逻辑,使用React状态管理流程阶段,添加状态锁防止重复触发,同时修复定时器和时间计算逻辑:

import * as React from 'react';
import { Pressable, Text, View } from 'react-native';
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { SafeAreaProvider } from 'react-native-safe-area-context';
import styles from './Styles';
import { entireScreenWidth } from '../App';

// 定义流程阶段:0=初始(青色),1=等待(红色),2=测试(绿色)
const PHASES = {
  INIT: 0,
  WAITING: 1,
  TESTING: 2
};

const colours = ['cyan', 'red', 'lime']; 

export default function ReactionScreen({navigation}) {
  const [currentPhase, setCurrentPhase] = React.useState(PHASES.INIT);
  const [reactionTime, setReactionTime] = React.useState(null);
  const [timerId, setTimerId] = React.useState(null);
  const startTimeRef = React.useRef(null);

  const maxDelay = 5000;
  const minDelay = 500;

  // 清理定时器(组件卸载或流程重置时)
  React.useEffect(() => {
    return () => {
      if (timerId) clearTimeout(timerId);
    };
  }, [timerId]);

  function startTest() {
    // 只有初始状态才能启动测试
    if (currentPhase !== PHASES.INIT) return;

    // 进入等待阶段(红色)
    setCurrentPhase(PHASES.WAITING);
    setReactionTime(null);

    // 生成随机延迟
    const randomDelay = Math.random() * (maxDelay - minDelay) + minDelay;
    const id = setTimeout(() => {
      // 进入测试阶段(绿色),记录开始时间
      setCurrentPhase(PHASES.TESTING);
      startTimeRef.current = performance.now();
    }, randomDelay);

    setTimerId(id);
  }

  function endTest() {
    // 只有测试阶段松开才计算反应时间
    if (currentPhase !== PHASES.TESTING) {
      // 如果在等待阶段松开,直接重置流程
      resetTest();
      return;
    }

    // 计算反应时间
    const finishTime = performance.now();
    const time = Math.round(finishTime - startTimeRef.current);
    setReactionTime(time);

    // 重置为初始状态
    resetTest();
  }

  function resetTest() {
    if (timerId) clearTimeout(timerId);
    setTimerId(null);
    setCurrentPhase(PHASES.INIT);
  }

  return (
    <SafeAreaProvider style={{ backgroundColor: colours[currentPhase], flex: 1 }}>
      <Pressable
        onPressIn={startTest}
        onPressOut={endTest}
        style={{ flex: 1, backgroundColor: 'transparent' }}
        android_ripple={{ color: 'blue', borderless: false, foreground: true }}
      >
        <MaterialCommunityIcons
          name="lightning-bolt"
          size={0.25 * entireScreenWidth}
          color="#7F00FF"
          style={[styles.buttonIcon, { textAlign: 'center', bottom: '-30%' }]}
        />
        <Text style={[styles.buttonLabel(0.1), { textAlign: 'center', bottom: '-60%' }]}>
          {currentPhase === PHASES.INIT ? 'Press to Start' : 
           currentPhase === PHASES.WAITING ? 'Wait for Green' : 
           'Release Now!'}
        </Text>
        {reactionTime && (
          <Text style={{ textAlign: 'center', marginTop: 20, fontSize: 24, fontWeight: 'bold' }}>
            Your reaction time: {reactionTime}ms
          </Text>
        )}
      </Pressable>
    </SafeAreaProvider>
  );
}
关键改动说明
  • 使用currentPhase状态管理流程阶段,替代全局变量c,确保React状态同步。
  • 通过currentPhase判断流程状态,只有初始状态允许触发startTest,避免重复启动流程。
  • 用useRef存储startTime,避免状态更新导致的异步问题。
  • 每次启动测试时生成随机延迟,并在重置流程或组件卸载时清理定时器,防止内存泄漏和状态混乱。
  • 只有在绿色测试阶段松开时才计算反应时间,等待阶段松开直接重置流程,符合测试逻辑。
  • 更新提示文本,根据当前阶段显示对应指引,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 16:25:27