Redux Toolkit 将状态保存到本地存储

Mr.*_*ody 11 typescript reactjs react-redux redux-toolkit

我正在使用 redux-toolkit,并且尝试在每次更新商店后将状态保存到本地存储,而不使用任何第三方库。原因是 redux-persist 不再更新,我不知道有什么好的替代方案。经过大量时间寻找解决方案后,我想出了使用createListenerMiddleware.

import { configureStore, createListenerMiddleware } from "@reduxjs/toolkit";
import counterSlice, { decrement, increment } from "../Slices/counterSlice";

const listenerMiddleware = createListenerMiddleware()
listenerMiddleware.startListening({
    actionCreator: increment,
    effect: () => (
        localStorage.setItem('count', JSON.stringify(store.getState().counter))
    )
})
const listenerMiddleware2 = createListenerMiddleware()
listenerMiddleware.startListening({
    actionCreator: decrement,
    effect: () => (
        localStorage.setItem('count', JSON.stringify(store.getState().counter))
    )
})
const counterState = JSON.parse(localStorage.getItem('count') || "null")
export const store = configureStore({
    preloadedState: {
        counter: counterState === null ? { value: 0 } : counterState
    },
    reducer: {
        counter: counterSlice
    },
    middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(listenerMiddleware2.middleware, listenerMiddleware.middleware)
})

export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
Run Code Online (Sandbox Code Playgroud)

有人可以告诉我这是否是一个好主意,如果不是,是否还有其他正确的方法。

Lin*_*ste 16

您的方向是正确的,但有一些变化:

访问状态

您应该从回调的参数访问该函数,而不是store直接使用变量来调用。getState()getState()effect

effect: (action: Action, listenerApi: ListenerApi) => void | Promise<void>
Run Code Online (Sandbox Code Playgroud)

您的effect函数使用两个参数调用:action触发效果的 和listenerApi对象,它使您可以访问getState()许多其他实用程序

侦听器中间件不知道存储的 TypeScript 类型,因此您需要以某种方式让它知道。实现此目的的一种方法是aslistenerApi.getState()调用时使用内联断言。

listenerMiddleware.startListening({
  actionCreator: increment,
  effect: (action, listenerApi) =>
    localStorage.setItem("count", JSON.stringify((listenerApi.getState() as RootState).counter))
});
Run Code Online (Sandbox Code Playgroud)

您还可以按照文档的TypeScript 用法TypedStartListening部分并使用实用程序类型。

处理多个动作

您不需要多个侦听器中间件实例,因为您可以将多个侦听器附加到同一中间件。startListening对同一变量进行多次简单调用listenerMiddleware

然而,在这种情况下,startListening您只需要一个电话即可!您的两个案例已经有相同的effect回调。但我们需要能够匹配incrementdecrement行动。侦听器可以通过几种不同的方式来检测匹配的操作。actionCreator我们将使用该属性,而不是只能匹配单个操作的using matcherisAnyOf我们在实用程序的帮助下创建了一个匹配器函数。

我们最终的中间件如下所示:

import { createListenerMiddleware, isAnyOf } from "@reduxjs/toolkit";
import { decrement, increment } from "./slice";
import type { RootState } from "./index";

export const listenerMiddleware = createListenerMiddleware();
listenerMiddleware.startListening({
  matcher: isAnyOf(increment, decrement),
  effect: (action, listenerApi) =>
    localStorage.setItem(
      "count",
      JSON.stringify((listenerApi.getState() as RootState).counter)
    )
});
Run Code Online (Sandbox Code Playgroud)

完整的 CodeSandbox 演示