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

React Navigation 6登出后登录屏幕重复渲染两次问题求助

问题现象
  • 应用内执行登出操作时,出现登录屏幕重复渲染两次的异常
  • 触发规律:仅在登录后导航到其他页面、再返回初始路由的场景下触发;登录后未离开初始路由直接登出时,登录页正常仅渲染一次
  • 技术背景:项目使用Redux结合AsyncStorage实现认证流程管控,使用React Navigation 6(该版本已移除旧版SwitchNavigator,旧版替换导航器的方案无法适用)
关联代码

Redux Reducer(user.js)

import {UPDATE_USER} from '../actions/actionTypes';

const initialState = {
  userdata: {},
  loginStatus: -1, // -1 == loading, 0 = not logged in, 1 == logged in
};

const updateUser = (state, action) => {
  let ud = action.userdata;

  return {...state, userdata: Object.assign({}, ud), loginStatus: ud ? 1 : 0};
};

const userReducer = (state = initialState, action) => {
  switch (action.type) {
    case UPDATE_USER:
      return updateUser(state, action);
    default:
      return state;
  }
};

export default userReducer;

根加载组件(LoadingScreen.js)

import React, {useEffect, useState, useRef} from 'react';
//ThirdParty
//import CustomSplashScreen from 'react-native-splash-screen';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {NavigationContainer} from '@react-navigation/native';

//Redux
import {updateUser} from '../../redux/actions/userActions';
import {useSelector} from 'react-redux';
import {useDispatch} from 'react-redux';

//Import STACK NAVIGATORS
import AuthNavigator from '../../navigator/AuthNavigator';
import MainNavigator from '../../navigator/MainNavigator';

function LoadingScreen() {
  const ref = useRef();
  const loginStatus = useSelector((state) => state.user.loginStatus);
  const dispatch = useDispatch();
  
  useEffect(() => {
    console.log('loginStatus', loginStatus);


    async function getAsyncData() {

      let data = await AsyncStorage.getItem('data');
      let dataParsed = JSON.parse(data);
      console.log("AsyncData: "+data);

      //Update redux state
      dispatch(updateUser(dataParsed)); 
    }

    getAsyncData();
  });

  if (loginStatus === -1) {
    // We haven't finished checking for the user logged in or not
    return <View style={styles.container} />;
  }

  ref && ref.current && ref.current.animateNextTransition();

  return (
    <NavigationContainer>
      <Transitioning.View ref={ref} transition={TRANSITION} style={styles.transitionContainer}>
        {loginStatus === 1 && <MainNavigator />} // STACK NAVIGATOR WHEN SIGNED IN
        {loginStatus === 0 && <AuthNavigator />} // STACK NAVIGATOR WHEN SIGNED OUT
      </Transitioning.View>
    </NavigationContainer>
  );
}

export default LoadingScreen;

登出方法实现

const signOutAsync = async () => {
   console.log("Begin Logout");
   dispatch(updateUser(null));
   await AsyncStorage.clear();
};
问题根因

代码里存在两个核心问题共同导致重复渲染:

  1. 根组件的useEffect未传入依赖数组,按照React规则,不传第二个参数的effect会在组件每次重渲染时都执行。也就是说每次登录状态变化、组件重渲染,都会重新读取一次AsyncStorage的用户数据、重复触发updateUser的dispatch动作。
  2. 登出逻辑顺序错误:先更新Redux登录状态为未登录,再异步清除本地存储。两个操作之间存在时间差:状态更新后组件立刻重渲染,触发无依赖的effect读取AsyncStorage,此时存储清除操作还没完成,会读到之前存储的有效用户信息,再次dispatch把登录状态改回已登录,等存储清除完成后又会触发状态变更,最终导致登录页重复渲染。登录后未导航过的场景下导航树状态简单,没有触发重渲染的间隙,所以不会复现问题。
修复方案

1. 修正useEffect依赖,避免重复执行初始化逻辑

给读取本地存储的useEffect传入空依赖数组,让该逻辑仅在组件首次挂载时执行一次,匹配“启动时读取本地登录态”的设计目的:

useEffect(() => {
  console.log('loginStatus', loginStatus);

  async function getAsyncData() {
    let data = await AsyncStorage.getItem('data');
    let dataParsed = JSON.parse(data);
    console.log("AsyncData: "+data);
    dispatch(updateUser(dataParsed)); 
  }

  getAsyncData();
}, []); // 新增空依赖数组

react-redux中dispatch的引用是稳定的,不需要加入依赖数组。

2. 调整登出逻辑顺序,消除状态更新间隙

把清除本地存储的操作放到Redux状态更新之前,保证存储操作完成后再切换全局登录状态,避免中间状态触发异常:

const signOutAsync = async () => {
   console.log("Begin Logout");
   await AsyncStorage.clear(); // 先清除本地存储
   dispatch(updateUser(null)); // 存储清空后再更新全局登录状态
};

3. (可选优化)明确导航树key,避免React复用组件状态

给两个条件渲染的导航器设置独立key,帮助React明确区分两个独立的导航树,避免状态复用导致的渲染异常:

<Transitioning.View ref={ref} transition={TRANSITION} style={styles.transitionContainer}>
  {loginStatus === 1 
    ? <MainNavigator key="main-app" />
    : <AuthNavigator key="auth-flow" />
  }
</Transitioning.View>

React Navigation 6本身已经支持通过条件渲染实现认证流,不需要依赖已移除的SwitchNavigator,以上修复完成后即可解决登录页重复渲染的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:12:33