React Navigation v5中navigation.navigate失效及Firebase鉴权跳转问题
嘿,我之前也踩过这个坑!你遇到的TypeError: undefined is not an object (evaluating '_this.props.navigation.navigate')错误,本质原因是你的LoadingScreen组件没有拿到React Navigation注入的navigation props——因为它不是作为导航栈里的屏幕组件被渲染的,而是直接放在App.js里返回,不在导航容器的上下文范围内,所以props.navigation自然是undefined。
下面给你两种可行的解决方案,推荐第一种,结构更清晰:
方案一:将LoadingScreen加入根导航栈
把LoadingScreen、AuthStack、BottomTabs都统一放到一个根栈里,让React Navigation能给LoadingScreen注入navigation props。
步骤1:修改App.js的导航结构
import React from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; import LoadingScreen from './Loading'; import AuthStack from './AuthStack'; import BottomTabs from './BottomTabs'; const RootStack = createStackNavigator(); export default function App() { return ( <NavigationContainer> <RootStack.Navigator initialRouteName="Loading" screenOptions={{ headerShown: false }} // 隐藏所有栈的头部 > <RootStack.Screen name="Loading" component={LoadingScreen} /> <RootStack.Screen name="AuthStack" component={AuthStack} /> <RootStack.Screen name="BottomTabs" component={BottomTabs} /> </RootStack.Navigator> </NavigationContainer> ); }
步骤2:修改Loading.js的auth监听逻辑
现在LoadingScreen已经是根栈的一员,能正常拿到navigation props了,记得用replace代替navigate,避免用户按返回键回到Loading页面,还要取消订阅防止内存泄漏:
import React, { Component } from 'react'; import { View, ActivityIndicator, StyleSheet } from 'react-native'; import firebase from 'firebase'; class LoadingScreen extends Component { componentDidMount() { // 订阅auth状态变化 this.authUnsubscribe = firebase.auth().onAuthStateChanged(user => { if (user) { // 已登录,跳转到底部标签页 this.props.navigation.replace('BottomTabs'); } else { // 未登录,跳转到登录注册栈 this.props.navigation.replace('AuthStack'); } }); } componentWillUnmount() { // 取消订阅,防止内存泄漏 this.authUnsubscribe(); } render() { return ( <View style={styles.container}> <ActivityIndicator size="large" color="#0000ff" /> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); export default LoadingScreen;
方案二:用withNavigation高阶组件包裹LoadingScreen
如果你不想调整导航结构,可以用withNavigation把LoadingScreen包裹起来,让它能获取导航上下文:
步骤1:修改Loading.js的导出
import React, { Component } from 'react'; import { View, ActivityIndicator, StyleSheet } from 'react-native'; import firebase from 'firebase'; import { withNavigation } from '@react-navigation/compat'; // 引入高阶组件 class LoadingScreen extends Component { // 你的componentDidMount和render逻辑和之前一样 componentDidMount() { firebase.auth().onAuthStateChanged(user => { if (user) { this.props.navigation.replace('BottomTabs'); } else { this.props.navigation.replace('AuthStack'); } }); } render() { return ( <View style={styles.container}> <ActivityIndicator size="large" color="#0000ff" /> </View> ); } } // 用withNavigation包裹组件后导出 export default withNavigation(LoadingScreen);
步骤2:确保App.js的导航容器包裹所有内容
你的App.js需要保证NavigationContainer包裹了AuthStack和BottomTabs,这样withNavigation才能拿到导航上下文:
import React from 'react'; import { NavigationContainer } from '@react-navigation/native'; import LoadingScreen from './Loading'; export default function App() { return ( <NavigationContainer> <LoadingScreen /> </NavigationContainer> ); }
注意事项
- 优先用
replace而不是navigate:这样跳转后,LoadingScreen会从导航栈中移除,用户按返回键不会回到加载页面 - 一定要取消auth状态订阅:在
componentWillUnmount里调用订阅返回的函数,防止内存泄漏 - 确认Firebase已正确初始化:如果auth监听没触发,检查Firebase配置是否正确,有没有在App启动时初始化
内容的提问来源于stack exchange,提问作者Unaidu
相关产品推荐
相关产品推荐

