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

React Native:解决刷新/重启App时Redux获取AsyncStorage Token为undefined

问题分析与解决方案

问题根源

你遇到的核心问题是异步操作的时序问题:

  • getData()是异步函数,调用后会立即返回一个Promise,不会阻塞后续代码执行。
  • 当你执行console.log(savedToken)和创建initialState时,await AsyncStorage.getItem('token')还未完成,savedToken仍保持初始的undefined值。
  • 虽然getData内部能打印到Token,但这是在异步操作完成后才执行的,此时initialState已经创建完毕,无法再被更新。

正确实现方式

我们可以通过Redux Toolkit的createAsyncThunk来异步加载本地存储的Token,并在App启动时触发这个操作,确保Token被正确加载到Redux状态中。

步骤1:创建加载Token的异步Thunk

在你的user slice文件中,添加一个异步Thunk用于从AsyncStorage获取Token:

import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
import { User, LoginPayload, LoginPayloadError } from './interface';
import { login } from '../../service/authService';
import AsyncStorage from '@react-native-async-storage/async-storage';

// 定义异步Thunk,用于加载本地存储的Token
export const loadSavedToken = createAsyncThunk(
  'user/loadSavedToken',
  async () => {
    const token = await AsyncStorage.getItem('token');
    return token || ''; // 如果没有Token则返回空字符串
  }
);

步骤2:修改Slice的初始状态与Reducer

调整slice的初始状态,并在extraReducers中处理loadSavedToken的完成状态:

const initialState: User = {
  token: '', // 初始值设为空,后续通过异步操作更新
  id: 0,
  email: '',
  nicename: '',
  firstName: '',
  lastName: '',
  displayName: '',
  role: '',
  loading: false,
  error: '',
};

const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {},
  extraReducers: builder => {
    builder
      // 处理加载Token的完成状态
      .addCase(loadSavedToken.fulfilled, (state, action: PayloadAction<string>) => {
        state.token = action.payload;
      })
      // 处理登录请求中状态
      .addCase(login.pending, (state) => {
        state.loading = true;
      })
      // 处理登录成功状态
      .addCase(login.fulfilled, (state, action: PayloadAction<User>) => {
        // 直接存储Token到AsyncStorage,无需包裹额外函数
        AsyncStorage.setItem('token', action.payload.token);
        // 直接修改state(RTK内置Immer支持不可变更新)
        state.loading = false;
        state.token = action.payload.token;
        state.id = action.payload.id;
        state.email = action.payload.email;
        state.nicename = action.payload.nicename;
        state.firstName = action.payload.firstName;
        state.lastName = action.payload.lastName;
        state.displayName = action.payload.displayName;
        state.role = action.payload.role;
      })
      // 处理登录失败状态
      .addCase(login.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload as LoginPayloadError;
      });
  },
});

export default userSlice.reducer;

步骤3:在App启动时触发Token加载

在你的根组件(如App.tsx或App.js)中,使用useEffect和useDispatch触发loadSavedToken:

import { useDispatch } from 'react-redux';
import { useEffect } from 'react';
import { loadSavedToken } from './path/to/userSlice';

function App() {
  const dispatch = useDispatch();

  useEffect(() => {
    // App启动时加载本地Token
    dispatch(loadSavedToken());
  }, [dispatch]);

  // 其他组件逻辑...
}

export default App;

额外优化点

  • 避免在login.fulfilled中返回新的state对象:RTK内置Immer库,允许直接修改state,代码更简洁且符合规范。
  • 不需要为AsyncStorage.setItem单独定义函数:直接调用即可,这是异步副作用操作,不影响Redux状态的同步更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:56:21