useEffect内调用React Navigation的navigation.replace()导致应用崩溃如何解决
问题原因
- 外层的
try/catch完全无效:你包裹的是同步代码逻辑,SecureStore.getItemAsync是异步Promise,它抛出的异常不会被外层同步的try/catch捕获,导致出现未捕获的Promise异常直接触发崩溃。 - 异步执行导航操作时,组件可能已经被卸载/navigation对象已失效:你在Promise的回调里直接调用
navigation.replace,如果此时这个重定向页面已经被导航栈移除,调用navigation方法就会触发崩溃。 - 部分版本React Navigation存在兼容问题:组件挂载完成前调用导航方法会触发异常,空依赖useEffect的执行时机是组件第一次渲染完成后,但部分场景下导航绑定还没完全完成,直接调用replace会出错。
- 你在else分支没有等待
setItemAsync执行完成就跳转,也可能出现存储操作没完成、页面先卸载导致的异常。
修复后的代码
import React, { useEffect, useRef } from 'react' import * as SecureStore from 'expo-secure-store' import { SafeAreaProvider } from 'react-native-safe-area-context' import { ActivityIndicator } from 'react-native-paper' export default function RedirectScreen({ navigation }) { // 标记组件是否挂载,避免组件卸载后执行导航 const isMountedRef = useRef(true) useEffect(() => { // 组件卸载时修改标记 return () => { isMountedRef.current = false } }, []) useEffect(() => { // 用async/await写法更易读,也能正确捕获异步异常 const checkInitialLaunch = async () => { try { const val = await SecureStore.getItemAsync('initialLaunch') // 只有组件还挂载的时候才执行导航 if (!isMountedRef.current) return if (val) { navigation.replace('AuthScreen') } else { await SecureStore.setItemAsync('initialLaunch', 'yes') if (!isMountedRef.current) return navigation.replace('Onboarding') } } catch (error) { console.log('检测首次启动出错', error) // 异常场景兜底导航,避免页面卡住 if (isMountedRef.current) { navigation.replace('AuthScreen') } } } // 加极短延迟,适配部分React Navigation版本导航未绑定完成的问题 const timer = setTimeout(checkInitialLaunch, 100) return () => clearTimeout(timer) }, [navigation]) return ( <SafeAreaProvider style={{ justifyContent: 'center', alignItems: 'center', }} > <ActivityIndicator /> </SafeAreaProvider> ) }
内容的提问来源于stack exchange,提问作者Emmanuel Yeboah
相关产品推荐
相关产品推荐

