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
相关产品推荐
相关产品推荐

