React-Navigation:根组件如何基于认证状态实现页面跳转?
解决方法:正确调用导航器实现自动跳转
你遇到的问题很典型——直接调用MainNavigator.navigate是行不通的,因为MainNavigator是你通过SwitchNavigator创建的导航器组件,而不是可以直接调用导航方法的navigation实例对象。下面给你几种可行的方案,结合你的redux认证场景来实现自动跳转:
方案一:动态设置导航器的初始路由(最简洁)
既然你已经通过redux获取了token状态,不妨在渲染导航器的时候,直接根据token的有效性动态指定初始页面。这样App启动时就会直接进入对应的页面,不需要手动调用navigate:
首先调整导航器代码(React Navigation v2+需要用createAppContainer包裹导航器):
import { createSwitchNavigator, createAppContainer } from 'react-navigation'; const SwitchNav = createSwitchNavigator({ intro: { screen: introScreen }, login: { screen: loginScreen }, Home: { screen: homeScreen } }); export const MainNavigator = createAppContainer(SwitchNav);
然后修改Application组件的render方法,根据token动态传递初始路由:
import React, { Component } from "react"; import { MainNavigator } from "./src/navigation"; import { connect } from "react-redux"; class Application extends Component { _checkToken(token) { // 这里保留你的token验证逻辑,示例简单判断token是否存在 return !!token; } render() { // 根据token状态决定初始路由 const initialRoute = this._checkToken(this.props.token) ? "Home" : "login"; return <MainNavigator initialRouteName={initialRoute} />; } } const mapStateToProps = state => { return { token: state.auth.token }; }; export default connect(mapStateToProps)(Application);
这样一来,App启动时会直接根据token状态进入Home或Login页面,redux-persist持久化token后,下次打开App也会自动进入对应页面。
方案二:使用导航服务(NavigationService)实现全局跳转
如果你的场景需要在组件外部或者其他地方调用导航方法,推荐创建一个导航服务来保存导航实例:
- 首先创建
NavigationService.js文件:
import { NavigationActions } from 'react-navigation'; let _navigator; function setTopLevelNavigator(navigatorRef) { _navigator = navigatorRef; } function navigate(routeName, params) { _navigator.dispatch( NavigationActions.navigate({ routeName, params, }) ); } // 可按需添加其他导航方法,比如goBack等 export default { navigate, setTopLevelNavigator, };
- 修改导航器代码,通过ref保存导航实例:
import { createSwitchNavigator, createAppContainer } from 'react-navigation'; import NavigationService from './NavigationService'; const SwitchNav = createSwitchNavigator({ intro: { screen: introScreen }, login: { screen: loginScreen }, Home: { screen: homeScreen } }); const AppContainer = createAppContainer(SwitchNav); export class MainNavigator extends React.Component { render() { return ( <AppContainer ref={navigatorRef => { NavigationService.setTopLevelNavigator(navigatorRef); }} /> ); } }
- 在Application组件中使用导航服务跳转:
import React, { Component } from "react"; import { MainNavigator } from "./src/navigation"; import { connect } from "react-redux"; import NavigationService from './NavigationService'; class Application extends Component { _checkToken(token) { // 保留你的token验证逻辑 return true; } _isLoggedin() { if (this._checkToken(this.props.token)) { NavigationService.navigate("Home"); } else { NavigationService.navigate("login"); } } componentDidMount() { this._isLoggedin(); } componentDidUpdate(prevProps) { // 加判断避免无限循环,仅在token变化时执行跳转 if (prevProps.token !== this.props.token) { this._isLoggedin(); } } render() { return <MainNavigator />; } } const mapStateToProps = state => { return { token: state.auth.token }; }; export default connect(mapStateToProps)(Application);
补充:原代码失效的原因
MainNavigator是通过createSwitchNavigator创建的导航器组件,它本身并没有navigate方法。真正可以调用导航方法的是navigation对象——这个对象是React Navigation通过props传递给各个屏幕组件的,或者通过导航容器的ref获取到的实例。所以直接调用MainNavigator.navigate自然会失效。
内容的提问来源于stack exchange,提问作者MadAlert
相关产品推荐
相关产品推荐

