You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 21:01:36