React Native中AsyncStorage持久化Redux状态遇TypeError问题
React Native 中 redux-persist 持久化数组状态触发
TypeError 的解决方法 问题
在React Native应用中使用AsyncStorage配合redux-persist持久化Redux数组状态时,出现错误:
TypeError: undefined is not a function (near '...state.reduce...')
已确认state对象非空,但无法定位具体未定义项。
相关代码
App.js
import Main from "./src/components/Main" import { NativeRouter } from "react-router-native" import { createStore } from "redux" import { Provider } from "react-redux" import reducer from "./src/reducer" import AsyncStorage from "@react-native-async-storage/async-storage" import { persistStore, persistReducer } from "redux-persist" import { PersistGate } from "redux-persist/integration/react" import Text from "./src/components/Text" const persistConfig = { key: "root", storage: AsyncStorage, } const persistedReducer = persistReducer(persistConfig, reducer) const store = createStore(persistedReducer) const persistor = persistStore(store) export default function App() { return ( <NativeRouter> <Provider store={store}> <PersistGate loading={<Text>Loading...</Text>} persistor={persistor}> <Main /> </PersistGate> </Provider> </NativeRouter> ) }
reducer.js
const reducer = (state = [], action) => { switch (action.type) { case "NEW_NOTE": { console.log("state :>> ", state) const max = state.reduce( (prev, current) => { // if (!current) return prev return current.id > prev.id ? current : prev }, { id: 0, body: "" } ) const newNote = { id: max.id + 1, body: "" } return state.concat(newNote) } case "UPDATE_NOTE": { const newNotes = state.filter((note) => action.data.id !== note.id) return [action.data, ...newNotes] } case "DELETE_NOTE": { return state.filter((note) => action.id !== note.id) } default: { return state } } } export default reducer
问题排查
排查后发现,persistReducer会将原本的数组状态转换为键值对形式的对象:
- 未持久化时的state(数组):
[{"body": "Ddtstostksoyoyyxcuj", "id": 2}, {"body": "Ftistldpufipf Hhxgjbv", "id": 1}]
- 持久化后的state(对象):
{"0": {"body": "my first note", "id": 1}, "1": {"body": "my second note", "id": 2}, "2": {"body": "my third note", "id": 3}}
此外,持久化后的state还会额外添加_persist属性:
{"0": {"body": "Hi", "id": 7}, "1": {"body": "", "id": 8}, "2": {"body": "", "id": 9}, "_persist": {"rehydrated": true, "version": -1}}
因为对象没有数组的reduce、filter等方法,所以调用这些方法时触发错误。
修复方案
1. 修改Reducer
在Reducer处理action前,将state转换为数组:
const reducer = (state = [], action) => { state = Object.values(state) switch (action.type) { case "NEW_NOTE": { console.log("state :>> ", state) const max = state.reduce( (prev, current) => { // if (!current) return prev return current.id > prev.id ? current : prev }, { id: 0, body: "" } ) const newNote = { id: max.id + 1, body: "" } return state.concat(newNote) } case "UPDATE_NOTE": { const newNotes = state.filter((note) => action.data.id !== note.id) return [action.data, ...newNotes] } case "DELETE_NOTE": { return state.filter((note) => action.id !== note.id) } default: { return state } } } export default reducer
2. 修改状态选择器
在使用useSelector获取状态时,将对象转换为数组并移除最后一个元素(即_persist属性对应的项):
const notes = useSelector((state) => Object.values(state).slice(0, -1))
内容的提问来源于stack exchange,提问作者George Garman
相关产品推荐
相关产品推荐

