如何在React-Native中使用Redux Slice控制AsyncStorage?
问题分析与解决方案
问题根源
你的代码错误出在Redux reducer中执行了异步副作用操作:AsyncStorage.setItem和AsyncStorage.clear都是异步Promise操作,而Redux的reducer必须是纯函数——不能包含异步、IO等副作用,也不能在reducer中直接修改外部存储。
另外,Redux Toolkit使用Immer库处理状态的不可变性,它会把state包装成只读代理对象,异步操作可能在Immer的状态处理周期外尝试修改state,从而触发"Attempted to assign to readonly property"错误。
正确实现方式
我们需要把同步状态更新和异步存储操作完全分离:reducer只负责更新Redux状态,异步的存储操作放在组件或专门的异步逻辑中处理。
1. 修正Slice代码(仅处理同步状态更新)
import { createSlice } from "@reduxjs/toolkit"; const initialState = { isLoggedIn: false, cart: null } const userAuthSlice = createSlice({ name: 'userAuth', initialState, reducers: { setLogin: (state, action) => { state.isLoggedIn = action.payload.isLoggedIn; }, setLogout: (state) => { state.isLoggedIn = false; state.cart = null; // 同步清空购物车状态 }, setCart: (state, action) => { state.cart = action.payload.cart; }, startUp: (state, action) => { state.cart = action.payload.cart; state.isLoggedIn = action.payload.isLoggedIn; } } }); export const { setLogin, setLogout, setCart, startUp } = userAuthSlice.actions; export const selectIsLoggedIn = (state) => state.userAuth.isLoggedIn; export const selectCart = (state) => state.userAuth.cart; export default userAuthSlice.reducer;
2. 在组件中处理异步存储操作
调用dispatch更新Redux状态后,再执行AsyncStorage的异步操作,并处理可能的错误:
import { useDispatch } from 'react-redux'; import AsyncStorage from "@react-native-async-storage/async-storage"; import { setCart, setLogin, setLogout } from '../path/to/userAuthSlice'; // 设置购物车的逻辑 const handleUpdateCart = async (cartObj) => { const dispatch = useDispatch(); try { // 先更新Redux状态 dispatch(setCart({ cart: cartObj })); // 再异步存储到本地 await AsyncStorage.setItem("cart", JSON.stringify(cartObj)); } catch (error) { console.error('存储购物车失败:', error); // 可选:这里可以添加错误提示或状态回滚逻辑 } }; // 登录逻辑 const handleLogin = async () => { const dispatch = useDispatch(); try { dispatch(setLogin({ isLoggedIn: true })); await AsyncStorage.setItem("isLoggedIn", JSON.stringify(true)); } catch (error) { console.error('存储登录状态失败:', error); } }; // 登出逻辑 const handleLogout = async () => { const dispatch = useDispatch(); try { dispatch(setLogout()); await AsyncStorage.clear(); } catch (error) { console.error('清空本地存储失败:', error); } };
3. 应用启动时加载本地存储的初始状态
在根组件或专门的初始化组件中,读取本地存储的数据并同步到Redux:
import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import AsyncStorage from "@react-native-async-storage/async-storage"; import { startUp } from '../path/to/userAuthSlice'; const AppInitializer = () => { const dispatch = useDispatch(); useEffect(() => { const loadInitialState = async () => { try { // 读取本地存储的登录状态和购物车数据 const storedLoginStatus = await AsyncStorage.getItem("isLoggedIn"); const storedCart = await AsyncStorage.getItem("cart"); // 同步到Redux状态 dispatch(startUp({ isLoggedIn: storedLoginStatus ? JSON.parse(storedLoginStatus) : false, cart: storedCart ? JSON.parse(storedCart) : null })); } catch (error) { console.error('加载初始状态失败:', error); } }; loadInitialState(); }, [dispatch]); return null; // 该组件无需渲染UI }; export default AppInitializer;
最后在你的App组件中引入AppInitializer即可完成初始状态的加载。
内容的提问来源于stack exchange,提问作者Gursahb Webcyst
相关产品推荐
相关产品推荐

