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;
解决方案
一、处理异步状态并保留类型
修正工具函数的类型与逻辑
给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 {}; };异步初始化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)获取,安全性极高。
- iOS:调用
禁止使用未加密的AsyncStorage
AsyncStorage未做加密处理,直接存储JWT存在泄露风险,除非手动加密后存储,但复杂度远高于直接使用加密存储库。短期Token可选内存存储
有效期较短的access token,可直接存在Redux Store等内存容器中,但应用重启后会丢失,需通过refresh token重新获取。refresh token必须加密存储
refresh token有效期长,一旦泄露会导致用户身份被长期冒用,必须存入加密存储,绝对不能放在内存或未加密容器中。
内容的提问来源于stack exchange,提问作者Dezl
相关产品推荐
相关产品推荐

