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

React中useState的exercises在Alert确认后为空,如何排查?

问题原因及解决办法

核心原因:闭包捕获了旧的状态值

你的问题是闭包导致的状态捕获问题:

  • handleFinishWorkout函数在组件某次渲染时创建,会捕获当时的exercises状态值。
  • 设置navigation.setOptions的useEffect依赖仅包含navigation和title,当exercises更新时,该useEffect不会重新执行,因此headerLeft中的handleFinishWorkout始终是旧版本函数,它捕获的exercises始终是初始的空数组。
  • 而监听exercises的useEffect因依赖exercises,每次状态更新都会触发,所以能打印最新值,这就造成了看似矛盾的现象。

解决办法

办法1:更新依赖并包裹函数

用useCallback包裹handleFinishWorkout,确保仅当exercises、title或navigation变化时函数才重新创建,同时将其加入navigation.setOptions的useEffect依赖数组:

const handleFinishWorkout = React.useCallback(() => {
  Alert.alert(
    "Confirmation",
    "Are you sure you want to finish workout?",
    [
      { text: "No", style: "cancel" },
      {
        text: "Yes",
        onPress: () => {
          const workout: Workout = {
            title: title,
            start_training: new Date().toISOString(),
            end_training: new Date().toISOString(),
            exercises: exercises,
          };
          console.log(exercises);
          navigation.goBack();
        },
      },
    ],
    { cancelable: false },
  );
}, [exercises, title, navigation]);

React.useEffect(() => {
  navigation.setOptions({
    headerTitle: () => (
      <TextInput
        style={styles.headerTitleInput}
        value={title}
        onChangeText={handleChangeTitle}
      />
    ),
    headerLeft: () => (
      <TouchableOpacity onPress={handleFinishWorkout} style={{ marginLeft: 15 }}>
        <Text style={styles.headerButtonText}>Finish</Text>
      </TouchableOpacity>
    ),
  });
}, [navigation, title, handleFinishWorkout]);

办法2:用useRef保存最新状态

通过useRef实时同步exercises的最新值,在Alert回调中直接读取ref.current:

const exercisesRef = React.useRef<Exercise[]>([]);

React.useEffect(() => {
  exercisesRef.current = exercises;
}, [exercises]);

const handleFinishWorkout = () => {
  Alert.alert(
    "Confirmation",
    "Are you sure you want to finish workout?",
    [
      { text: "No", style: "cancel" },
      {
        text: "Yes",
        onPress: () => {
          const workout: Workout = {
            title: title,
            start_training: new Date().toISOString(),
            end_training: new Date().toISOString(),
            exercises: exercisesRef.current,
          };
          console.log(exercisesRef.current);
          navigation.goBack();
        },
      },
    ],
    { cancelable: false },
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 04:15:30