You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中JWT验证后单次导航至受保护页面的实现方案

Hey there! Let's work through your React Native JWT navigation problem step by step. You're dealing with two key issues: where to check for the JWT token on app launch, and how to avoid repeated navigation calls. Here's a practical, clean solution tailored to your code setup:

解决方案:React Native JWT Token检测与单次导航实现

一、应用启动时的Token检测位置

  • Move your token check to the root container component (your RootContainer) instead of the WelcomeScreen. Stack-based screen components like WelcomeScreen re-mount or re-render when navigating between routes, which causes your check logic to fire repeatedly.
  • Why this works: RootContainer is the entry point of your app, so it only mounts once when the app starts—ensuring your token check runs exactly once.

二、Avoid repeated navigate calls

Use one of these reliable methods to prevent redundant navigation:

  • Global navigation ref: Create a reusable navigation instance that doesn't depend on component props, making it easy to call navigation from any part of your app.
  • Route check: Verify if you're already on the target route before triggering navigation.
  • Redux state flag: Add a hasNavigated flag to your auth state to track whether you've already redirected the user.

具体代码修改示例

1. Create a global navigation service

First, make a new file navigationService.js to handle navigation outside screen components:

import { NavigationActions } from 'react-navigation';

let _navigator;

function setTopLevelNavigator(navigatorRef) {
  _navigator = navigatorRef;
}

function navigate(routeName, params) {
  _navigator.dispatch(
    NavigationActions.navigate({
      routeName,
      params,
    })
  );
}

function getCurrentRoute() {
  let route = _navigator.state.nav;
  while (route.routes) {
    route = route.routes[route.index];
  }
  return route.routeName;
}

export default {
  navigate,
  setTopLevelNavigator,
  getCurrentRoute,
};

2. Update RootContainer.js to handle token checks and navigation

Modify your root container to run the token check on launch, and trigger navigation only when needed:

import React, { Component } from 'react';
import { View, ActivityIndicator } from 'react-native';
import { connect } from 'react-redux';
import { createBottomTabNavigator } from 'react-navigation';
import WelcomeScreen from './WelcomeScreen';
import AuthScreen from './AuthScreen';
import MapScreen from './MapScreen';
import DeckScreen from './DeckScreen';
import ReviewScreen from './ReviewScreen';
import SettingsScreen from './SettingsScreen';
import navigationService from '../navigationService';
import { checkForToken } from '../actions'; // Your async token check action

class RootContainer extends Component {
  componentDidMount() {
    // Run token check once when the app starts
    this.props.checkForToken();
  }

  componentDidUpdate(prevProps) {
    // Trigger navigation ONLY when token is newly detected
    if (!prevProps.token && this.props.token) {
      const currentRoute = navigationService.getCurrentRoute();
      // Avoid navigation if we're already on the target screen
      if (currentRoute !== 'map') {
        navigationService.navigate('map');
      }
    }
  }

  render() {
    const MainNavigator = createBottomTabNavigator({
      welcome: { screen: WelcomeScreen },
      auth: { screen: AuthScreen },
      main: { 
        screen: createBottomTabNavigator({
          map: { screen: MapScreen },
          deck: { screen: DeckScreen },
          review: { 
            screen: createStackNavigator({
              review: { screen: ReviewScreen },
              settings: { screen: SettingsScreen }
            }) 
          }
        }) 
      }
    }, {
      lazy: true,
      navigationOptions: { tabBarVisible: false }
    });

    return (
      <View style={{ flex: 1 }}>
        {/* Show loading while checking for token */}
        {this.props.appLoading ? (
          <ActivityIndicator style={{ flex: 1 }} size="large" />
        ) : (
          <MainNavigator 
            ref={navigatorRef => {
              navigationService.setTopLevelNavigator(navigatorRef);
            }} 
          />
        )}
      </View>
    );
  }
}

const mapStateToProps = state => ({
  token: state.auth.token,
  appLoading: state.auth.appLoading
});

export default connect(mapStateToProps, { checkForToken })(RootContainer);

3. Simplify WelcomeScreen.js

Remove the redundant navigation logic from WelcomeScreen—it no longer needs to handle token-based redirection:

import React, { Component } from 'react';
import { Text, ActivityIndicator } from 'react-native';
import { connect } from 'react-redux';

class WelcomeScreen extends Component {
  render() {
    if (this.props.appLoading) {
      return <ActivityIndicator size="large" />;
    }

    // If token exists, don't render the welcome screen (RootContainer will redirect)
    if (this.props.token) {
      return null; // Or a loading spinner until navigation completes
    }

    return <Text>WelcomeScreen</Text>;
  }
}

const mapStateToProps = state => ({
  token: state.auth.token,
  appLoading: state.auth.appLoading
});

export default connect(mapStateToProps)(WelcomeScreen);

Add a hasNavigated flag to your auth state if you prefer using a Redux-based check instead of the route name:

const INITIAL_STATE = {
  token: null,
  appLoading: true,
  hasNavigated: false
};

export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case LOGIN_SUCCESS:
      return {
        ...state,
        token: action.payload,
        appLoading: false,
        hasNavigated: false
      };
    case 'MARK_NAVIGATED':
      return {
        ...state,
        hasNavigated: true
      };
    default:
      return state;
  }
};

Then update the componentDidUpdate in RootContainer to use this flag:

componentDidUpdate(prevProps) {
  if (!prevProps.token && this.props.token && !this.props.hasNavigated) {
    navigationService.navigate('map');
    this.props.dispatch({ type: 'MARK_NAVIGATED' });
  }
}

Key Takeaways

  • Global navigation ref: Eliminates the need to pass navigate via props, making navigation accessible from non-screen components like your root container.
  • Single-run check: By placing the token check in RootContainer, you ensure it only runs once on app launch.
  • Navigation guard: Either checking the current route or using a Redux flag prevents repeated navigation calls that break your app flow.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:07:15