React Native Expo项目Redux Persist在Android端重启后无法加载状态
Expo + redux-persist Android端重启后无法加载持久化状态问题
问题现象
用Expo创建项目并集成redux-persist做状态持久化后,出现以下差异:
- iOS端状态加载完全正常
- Android端仅在代码热重载时能正常读取存储的状态;App重启后无法获取持久化数据,仅能拿到初始状态
相关代码
store.js
import {combineReducers, configureStore} from '@reduxjs/toolkit' import {setFirstname, userSlice} from "./user/userSlice"; import AsyncStorage from '@react-native-async-storage/async-storage'; import { persistStore, persistReducer } from 'redux-persist' import {FLUSH, PAUSE, PERSIST, PURGE, REGISTER, REHYDRATE} from "redux-persist/es/constants"; const persistConfig = { key: 'root', storage: AsyncStorage, } const persistedReducer = persistReducer(persistConfig, userSlice.reducer) export const store = configureStore({ reducer: persistedReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: { ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], }, }), }) export const persistor = persistStore(store) export default store
app.js
import { StatusBar } from 'expo-status-bar'; import { StyleSheet } from 'react-native'; import React, {useEffect, useState} from 'react'; import BottomNav from "./app/navigations/BottomNav"; import 'react-native-gesture-handler' import StackNav from "./app/navigations/StackNav"; import {NavigationContainer} from "@react-navigation/native"; import {navigationRef} from "./app/navigations/RootNavigation"; import {Provider} from "react-redux"; import {persistor, store} from "./app/store/store"; import {PersistGate} from "redux-persist/integration/react"; import SpinningLogo from "./app/ui/SpinningLogo"; export default function App() { const [isAuth, setAuth] = useState(null) useEffect(() => { console.log(store.getState().userToken) if (store.getState().userToken){ setAuth(true) } }) return ( <Provider store={store}> <PersistGate loading={<SpinningLogo/>} persistor={persistor}> <NavigationContainer ref={navigationRef}> <StatusBar style="light" /> {isAuth ? ( <BottomNav/> ): <StackNav />} </NavigationContainer> </PersistGate> </Provider> ); } const styles = StyleSheet.create({ container: { }, });
解决方案
1. 修复状态判断时机与Redux用法问题
原代码直接调用store.getState()且useEffect无依赖项,会在PersistGate完成状态恢复前就执行,拿到初始状态。改用useSelector订阅状态变化,确保状态恢复后再更新导航逻辑:
import { StatusBar } from 'expo-status-bar'; import { StyleSheet } from 'react-native'; import React from 'react'; import BottomNav from "./app/navigations/BottomNav"; import 'react-native-gesture-handler' import StackNav from "./app/navigations/StackNav"; import {NavigationContainer} from "@react-navigation/native"; import {navigationRef} from "./app/navigations/RootNavigation"; import {Provider, useSelector} from "react-redux"; import {persistor, store} from "./app/store/store"; import {PersistGate} from "redux-persist/integration/react"; import SpinningLogo from "./app/ui/SpinningLogo"; // 抽离导航逻辑为子组件,内部使用useSelector订阅状态 const AppContent = () => { const userToken = useSelector(state => state.userToken) return ( <> <StatusBar style="light" /> {userToken ? <BottomNav/> : <StackNav />} </> ) } export default function App() { return ( <Provider store={store}> <PersistGate loading={<SpinningLogo/>} persistor={persistor}> <NavigationContainer ref={navigationRef}> <AppContent /> </NavigationContainer> </PersistGate> </Provider> ); } const styles = StyleSheet.create({ container: { }, });
2. 适配Android存储读取速度
Android端AsyncStorage读取速度慢于iOS,可在persistConfig中延长状态恢复超时时间:
const persistConfig = { key: 'root', storage: AsyncStorage, timeout: 10000 // 延长至10秒,确保Android有足够时间读取存储 }
3. 确保状态可序列化
redux-persist依赖JSON序列化存储状态,Android对序列化兼容性要求更严格,检查userSlice中的状态是否包含不可序列化类型(如函数、Symbol、未转字符串的Date对象),示例如下:
// userSlice.js 确保状态全为可序列化类型 import { createSlice } from '@reduxjs/toolkit' const initialState = { userToken: null, firstname: '', // 避免使用函数、原始Date对象等,日期建议转成ISO字符串存储 } export const userSlice = createSlice({ name: 'user', initialState, reducers: { setFirstname: (state, action) => { state.firstname = action.payload }, // 其他reducer逻辑 }, })
内容的提问来源于stack exchange,提问作者Moemen Hussein
相关产品推荐
相关产品推荐

