You need to enable JavaScript to run this app. React Native结合React Navigation5时useEffect同屏/返回/切后台不触发问题
优惠活动
大模型
产品
解决方案
定价
更多

React Native结合React Navigation5时useEffect同屏/返回/切后台不触发问题

要覆盖你提到的所有场景,需要同时处理三类触发时机:页面聚焦、应用前后台切换、停留当前页时的时间到达触发,具体实现如下:

1. 实现思路

  • 使用React Navigation提供的useFocusEffect处理页面聚焦时的校验,替代仅依赖静态变量触发的useEffect
  • 使用React Native内置的AppState监听应用从后台切回前台的事件,每次切回主动触发校验
  • 为当前选中的配送时间计算倒计时,到达过期时间点时自动触发校验,无需跳转页面即可执行逻辑

2. 完整修改代码

import * as React from 'react';
import {Text,View, Alert, Button, AppState} from 'react-native';
import { NavigationContainer, useFocusEffect } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { useNavigation } from '@react-navigation/native';

const Stack = createStackNavigator();

const deliveryDate = "2021-06-21";
const deliveryTime = "10:00-10:03";

const isTimeWindowExpired = (date: string, time: string) => {
    const [startTime] = time.split('-');
    const newDate = new Date(`${date}T${startTime}`);
    return newDate.getTime() < new Date().getTime();
};
        
function Home() {
    const navigation = useNavigation()
    return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>Home</Text>
            <Button
                title="Go to Details"
                onPress={() => navigation.navigate('details')}
            />
        </View>
    );
}

function SecondHome() {
    const navigation = useNavigation();
    const appState = React.useRef(AppState.currentState);
    const expirationTimer = React.useRef<NodeJS.Timeout | null>(null);

    // 通用校验逻辑
    const checkExpiration = React.useCallback(() => {
        const isExpired = isTimeWindowExpired(deliveryDate, deliveryTime);
        if (isExpired) {
            Alert.alert("您选择的时间已过期!");
            // 这里追加清空配送时间的逻辑
        }
        // 计算下一次需要触发校验的时间,设置定时器
        if (expirationTimer.current) clearTimeout(expirationTimer.current);
        const [startTime] = deliveryTime.split('-');
        const expireTime = new Date(`${deliveryDate}T${startTime}`).getTime();
        const now = Date.now();
        if (expireTime > now) {
            expirationTimer.current = setTimeout(checkExpiration, expireTime - now);
        }
    }, [deliveryDate, deliveryTime]);

    // 页面聚焦时触发校验
    useFocusEffect(
        React.useCallback(() => {
            checkExpiration();
            return () => {
                if (expirationTimer.current) clearTimeout(expirationTimer.current);
            };
        }, [checkExpiration])
    );

    // 监听应用前后台切换
    React.useEffect(() => {
        const subscription = AppState.addEventListener('change', nextAppState => {
            if (appState.current.match(/inactive|background/) && nextAppState === 'active') {
                // 应用从后台切回前台,触发校验
                checkExpiration();
            }
            appState.current = nextAppState;
        });

        return () => {
            subscription.remove();
            if (expirationTimer.current) clearTimeout(expirationTimer.current);
        };
    }, [checkExpiration]);

    return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Text>当前页面即可自动校验过期时间,切后台返回也会触发校验</Text>
            <Text>Home</Text>
            <Button
                title="Go back Home"
                onPress={() => navigation.goBack()}
            />
        </View>
    );
}

const App = () => {
    return (
        <NavigationContainer>
            <Stack.Navigator initialRouteName="home" detachInactiveScreens>
                <Stack.Screen name="home" component={Home} />
                <Stack.Screen name="details" component={SecondHome} />
            </Stack.Navigator>
        </NavigationContainer>
    );
};

export default App;

逻辑说明

  • 所有场景的校验逻辑复用同一个checkExpiration方法,避免逻辑重复
  • 定时器仅会在过期时间点触发一次,不会高频轮询,不会影响应用性能
  • 页面失焦、组件卸载时会自动清除定时器,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 15:06:05