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

React Native中Redux异步初始状态类型保留及JWT存储问询

问题描述

当前getStateFromAsyncStorage()返回Promise,无法直接传入createAppStore函数,需解决如何在获取异步状态后保留Partial<RootState>类型;同时想了解React Native中存储JWT的合适方案。


相关代码

store.ts

export const createAppReducer = () =>
  combineReducers({
    system: systemReducer,
    posts: postsReducer,
  });

const reducer = createAppReducer();
export type RootState = ReturnType<typeof reducer>;

export const createAppStore = (initialState?: Partial<RootState>) =>
  configureStore({
    reducer,
    preloadedState: initialState,
  });

utils.ts

import EncryptedStorage from 'react-native-encrypted-storage';

export const getStateFromAsyncStorage = () => {
  async function retrieveUserSession() {
    try {
      const session = await EncryptedStorage.getItem('user_session');
      if (!!session) {
        return {
          system: {
            userId: 'JSON.parse(session).userId',
            accessToken: 'JSON.parse(session).bmAccessToken',
            refreshToken: 'JSON.parse(session).bmRefreshToken',
          },
        };
      }
    } catch (error) {
      console.log(error);
    }
    return {}
  }

  const res = retrieveUserSession()

  return res;
};

App.tsx

const state = getStateFromAsyncStorage()

const store = createAppStore(state);

const Stack = createNativeStackNavigator();


const App = () => {
  return (
    <Provider store={store}>
      <NavigationContainer>
        <AuthStack />
      </NavigationContainer>
    </Provider>
  )
}

export default App;

解决方案

一、处理异步状态并保留类型

  1. 修正工具函数的类型与逻辑
    给getStateFromAsyncStorage明确返回类型,同时修复内部JSON解析的错误(原代码将解析代码误写为字符串):

    // utils.ts
    import EncryptedStorage from 'react-native-encrypted-storage';
    import type { RootState } from './store';
    
    export const getStateFromAsyncStorage = async (): Promise<Partial<RootState>> => {
      try {
        const session = await EncryptedStorage.getItem('user_session');
        if (session) {
          const parsedSession = JSON.parse(session);
          return {
            system: {
              userId: parsedSession.userId,
              accessToken: parsedSession.bmAccessToken,
              refreshToken: parsedSession.bmRefreshToken,
            },
          };
        }
      } catch (error) {
        console.log(error);
      }
      return {};
    };
    
  2. 异步初始化Store
    利用React的状态与副作用钩子处理异步流程,等待状态加载完成后再渲染Provider:

    // App.tsx
    import { useState, useEffect } from 'react';
    import { View, ActivityIndicator } from 'react-native';
    import { Provider } from 'react-redux';
    import { NavigationContainer } from '@react-navigation/native';
    import { createNativeStackNavigator } from '@react-navigation/native-stack';
    import { createAppStore } from './store';
    import { getStateFromAsyncStorage } from './utils';
    import AuthStack from './AuthStack';
    
    const Stack = createNativeStackNavigator();
    
    const App = () => {
      const [store, setStore] = useState(null);
    
      useEffect(() => {
        const initStore = async () => {
          const initialState = await getStateFromAsyncStorage();
          const appStore = createAppStore(initialState);
          setStore(appStore);
        };
        initStore();
      }, []);
    
      // 加载完成前显示占位组件
      if (!store) {
        return (
          <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <ActivityIndicator size="large" />
          </View>
        );
      }
    
      return (
        <Provider store={store}>
          <NavigationContainer>
            <AuthStack />
          </NavigationContainer>
        </Provider>
      );
    };
    
    export default App;
    

    此方案既保证initialState符合Partial<RootState>类型约束,又解决了Promise无法直接传入的问题。

二、React Native存储JWT的合适方案

  • 优先使用加密存储库
    你当前使用的react-native-encrypted-storage是优质选择,它会根据平台自动适配安全存储:

    • iOS:调用Keychain Services
    • Android:使用EncryptedSharedPreferences或Keystore
      这类存储不会被常规备份工具(如iCloud/Google Drive)获取,安全性极高。
  • 禁止使用未加密的AsyncStorage
    AsyncStorage未做加密处理,直接存储JWT存在泄露风险,除非手动加密后存储,但复杂度远高于直接使用加密存储库。

  • 短期Token可选内存存储
    有效期较短的access token,可直接存在Redux Store等内存容器中,但应用重启后会丢失,需通过refresh token重新获取。

  • refresh token必须加密存储
    refresh token有效期长,一旦泄露会导致用户身份被长期冒用,必须存入加密存储,绝对不能放在内存或未加密容器中。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 17:17:13