react-native-encrypted-storage结合redux-persist时状态未更新问题
Redux状态无法更新问题排查(redux-persist + react-native-encrypted-storage)
尝试用react-native-encrypted-storage配合redux-persist实现安全持久化存储,但调用setPersistedDataaction后,日志能打印但组件状态未更新。相关代码如下:
store.ts
import {combineReducers, configureStore} from '@reduxjs/toolkit'; import persistedReducer from './persistedSlice'; import { FLUSH, PAUSE, PERSIST, PURGE, REGISTER, REHYDRATE, persistReducer, persistStore, } from 'redux-persist'; import EncryptedStorage from 'react-native-encrypted-storage'; import {TypedUseSelectorHook, useDispatch, useSelector} from 'react-redux'; const combinedReducer = combineReducers({ persisted: persistedReducer, }); const persistedCombinedReducer = persistReducer( { key: 'root', storage: EncryptedStorage, whitelist: ['persisted'], }, combinedReducer, ); const createStores = () => { const store = configureStore({ reducer: persistedCombinedReducer, middleware: getDefaultMiddleware => getDefaultMiddleware({ serializableCheck: { ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], }, }), }); const persistedStore = persistStore(store); return {store, persistedStore}; }; const {store, persistedStore} = createStores(); export {store, persistedStore}; export type RootState = ReturnType<typeof store.getState>; export type AppDispatch = typeof store.dispatch; type DispatchFunc = () => AppDispatch; export const useAppDispatch: DispatchFunc = useDispatch; export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
persistedSlice.ts
import {PayloadAction, createSlice} from '@reduxjs/toolkit'; interface PersistedState { user?: { id: string; name: string; }; token?: string; } const initialState: PersistedState = {}; const persistedSlice = createSlice({ name: 'persisted', initialState, reducers: { setPersistedData(state, action: PayloadAction<PersistedState>) { console.log('AAAA: ', { state, data: action.payload, }); state = action.payload; }, }, }); export const {setPersistedData} = persistedSlice.actions; export default persistedSlice.reducer;
组件代码
import React from 'react'; import {useAppDispatch, useAppSelector} from './store'; import {Button, Text, View} from 'react-native'; import {setPersistedData} from './persistedSlice'; const Consumer = () => { const user = useAppSelector(state => state.persisted.user); const dispatch = useAppDispatch(); return ( <View> <Text>User info: {user ? JSON.stringify(user) : 'unknown'}</Text> <Button title="Set user" onPress={() => { dispatch( setPersistedData({ user: { id: '1', name: 'Mister A', }, token: 'abcA@@', }), ); }} /> </View> ); }; export default Consumer;
问题原因
在persistedSlice.ts的setPersistedDatareducer中,直接执行state = action.payload是无效的。Redux Toolkit的createSlice使用Immer库处理不可变状态,直接给state变量赋值只会改变局部变量的引用,不会修改Immer包装的原始状态对象,因此Redux无法检测到状态变化。
修复方案
修改setPersistedData的实现,有两种可行方式:
方式一:返回新的状态对象
直接返回action.payload,Immer会自动处理状态替换:
setPersistedData(_state, action: PayloadAction<PersistedState>) { console.log('AAAA: ', { data: action.payload, }); return action.payload; }
方式二:使用Immer的可变语法更新状态
通过Object.assign或者逐个属性赋值来修改原state对象:
setPersistedData(state, action: PayloadAction<PersistedState>) { console.log('AAAA: ', { state, data: action.payload, }); // 用Object.assign合并新数据到原状态 Object.assign(state, action.payload); // 或者逐个属性赋值(适合部分更新场景) // state.user = action.payload.user; // state.token = action.payload.token; }
选择其中一种方式修改后,Redux就能正确检测到状态变化,组件会重新渲染并展示更新后的user信息。
内容的提问来源于stack exchange,提问作者Dao Danh
相关产品推荐
相关产品推荐

