在React中使Redux工具箱保持持久化状态

1,272 阅读7分钟

通过Redux Persist库,开发者可以将Redux存储保存在持久性存储中,例如,本地存储。因此,即使在刷新浏览器后,网站状态仍将被保留。Redux Persist还包括一些方法,使我们能够定制被持久化和再水化的状态,所有这些方法都有一个容易理解的API。

在这篇文章中,我们将学习如何在React中使用Redux PersistRedux Toolkit。要跟上这篇文章,你应该熟悉React和Redux Toolkit。你的机器上还应该安装了Node.js。

设置React

我已经创建了一个使用Redux Toolkit进行状态管理的应用程序。我们将在本教程中使用它来学习Redux Persist如何工作。要开始,请克隆GitHub repo。你可以用以下命令来做。

$ git clone https://github.com/Tammibriggs/auth-app.git

$ cd auth-app

$ npm install

接下来,我们可以用npm start 命令启动应用程序。在我们的应用程序中,我们会看到一个表单,其中有一个字段可以输入我们的姓名和电子邮件。在输入所需的输入并提交表格后,我们将被带到我们的个人资料页面,该页面看起来类似于下面的图片。

React Profile Page

当我们刷新浏览器时,我们的数据就会丢失。让我们学习如何使用Redux Persist将状态保存在持久性存储中,这样即使在刷新后,数据仍会保持完整。我们还将学习如何定制被持久化的内容,并指定如何合并传入的状态。让我们开始吧!

用Redux Persist持久化状态

首先,我们将通过以下命令将Redux Persist添加到我们的应用程序。

$ npm i redux-persist

接下来,我们需要修改我们的商店,我们可以在克隆应用的src 目录下的redux 文件夹中找到。目前,我们的商店看起来像下面的代码。

// src/redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import userReducer from "./slices/userSlice";

export const store = configureStore({
  reducer: userReducer,
  devTools: process.env.NODE_ENV !== 'production',
})

我们将对我们的store.js 文件做以下修改,以使用Redux Persist。

// src/redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import userReducer from "./slices/userSlice";
import storage from 'redux-persist/lib/storage';
import { persistReducer, persistStore } from 'redux-persist';
import thunk from 'redux-thunk';

const persistConfig = {
  key: 'root',
  storage,
}

const persistedReducer = persistReducer(persistConfig, userReducer)

export const store = configureStore({
  reducer: persistedReducer,
  devTools: process.env.NODE_ENV !== 'production',
  middleware: [thunk]
})

export const persistor = persistStore(store)

在上面的代码中,我们将商店中的reducer 属性的值从userReducer 替换为persistedReducer ,这是一个具有配置的增强型减速器,可将userReducer 的状态持久化到本地存储。除了本地存储,我们还可以使用其他存储引擎,如 [sessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage)Redux Persist Cookie存储适配器

要使用不同的存储引擎,我们只需要用我们想使用的存储引擎来修改persistConfigstorage 属性的值。例如,要使用sessionStorage 引擎,我们首先要导入它,如下所示。

import storageSession from 'reduxjs-toolkit-persist/lib/storage/session'

然后,修改persistConfig ,使其看起来像下面的代码。

const persistConfig = {
  key: 'root',f
  storageSession,
}

在上面对存储的修改中,我们还包含了Thunk中间件,它将在非序列化的值到达还原器之前拦截并阻止它们的行动。当使用Redux Persist而不使用Thunk中间件时,我们会在浏览器的控制台中得到一个错误,阅读a non-serializable value was detected in the state

最后,我们把我们的存储作为参数传给了persistStore ,这是一个持久化和重新水化状态的函数。通过这个函数,我们的存储将被保存到本地存储中,即使在浏览器刷新后,我们的数据仍然会保留。

在大多数用例中,我们可能希望推迟我们应用程序的UI渲染,直到持久化的数据在Redux存储中可用。为此,Redux Persist包括 PersistGate组件。要使用PersistGate ,请到src 目录下的index.js 文件,并添加以下导入。

// src/index.js
import { persistor, store } from './redux/store';
import { PersistGate } from 'redux-persist/integration/react';

现在,修改render 的函数调用,使其看起来像下面的代码。

// src/index.js
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>
  </React.StrictMode>
);

在本节中,我们介绍了使用Redux Persist时的基本设置。现在,让我们来探索Redux Persist的可用选项和用例。

使用Redux Persist的嵌套持久主义

如果我们在Redux Toolkit中有两个或更多的还原器,如userReducernotesReducer ,并且我们想把它们添加到我们的存储中,我们可能会按如下方式配置存储。

const store = configureStore({
  reducer: {
    user: userReducer,
    notes: notesReducer
  },
})

我们也可以使用combineReducers ,如下所示,做同样的事情。

const rootReducer = combineReducers({ 
  user: userReducer,
  notes: NotesReducer
})

const store = configureStore({
  reducer: rootReducer
})

为了在这种情况下使用Redux Persist,我们将提供rootReducer 作为persistReducer 的参数,然后在我们的商店中用持久化的reducer替换rootReducer ,如下所示。

const rootReducer = combineReducers({ 
  user: userReducer,
  notes: NotesReducer
})

const persistedReducer = persistReducer(persistConfig, rootReducer)

const store = configureStore({
  reducer: persistedReducer
})

然而,如果我们想设置一个不同的配置呢?例如,假设我们想把userReducer 的存储引擎改为sessionStorage 。要做到这一点,我们可以使用嵌套持久化,这个功能允许我们嵌套persistReducer ,让我们有能力为还原器设置不同的配置。

下面是一个嵌套持久化的例子,我把userReducer 的存储改为sessionStorage

const rootPersistConfig = {
  key: 'root',
  storage,
}

const userPersistConfig = {
  key: 'user',
  storage: storageSession,
}

const rootReducer = combineReducers({
  user: persistReducer(userPersistConfig, userReducer),
  notes: notesReducer
})

const persistedReducer = persistReducer(rootPersistConfig, rootReducer)

const store = configureStore({
  reducer: persistedReducer
})

指定传入状态的合并方式

合并涉及到将持久化的状态保存回Redux商店。当我们的应用程序启动时,我们的初始状态被设置。不久之后,Redux Persist从存储中检索我们的持久化状态,然后覆盖任何初始状态。这个过程是自动进行的。

默认情况下,合并过程会自动合并一个级别的深度。比方说,我们有一个传入和初始状态,如下图。

{user: {name: 'Tammibriggs'}, isLoggedIn: true} // incoming state
{ user: {name: '', email: ''}, isLoggedIn: false, status: 'Pending'} // initial state

合并后的状态将看起来像下面的代码。

{ user: {name: 'Tammibriggs'}, isLoggedIn: true, status: 'Pending'} // reconciled/merged state

初始状态与传入状态和顶层属性值进行了合并。email 在传入状态中,这些被替换而不是合并,这就是为什么user 中的属性会丢失。在我们的代码中,这将看起来类似于下面的情况。

const mergedState = { ...initialState };

mergedState['user'] = persistedState['user']
mergedState['isLoggedIn'] = persistedState['isLoggedIn']

Redux Persist中的这种合并类型被称为autoMergeLevel1 ,它是Redux Persist中默认的状态调节器。其他的状态调和器包括hardSet ,它用传入的状态完全覆盖初始状态,以及autoMergeLevel2 ,它合并了两层深度。

在我们之前的例子中,user 中的email 属性不会丢失。调和或合并后的状态将看起来像下面的代码。

{ user: {name: 'Tammibriggs' email:''}, isLoggedIn: true, status: 'Pending'} // reconciled/merged state

例如,要设置一个状态调节器,如果我们想使用autoMergeLevel2 ,我们只需要在persistConfig 中指定一个stateReconciler 属性。

import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';

const persistConfig = {
  key: 'root',
  storage,
  stateReconciler: autoMergeLevel2
}

自定义被持久化的内容

我们可以通过使用传递给persistReducerconfig 对象的blacklistwhitelist 属性来定制要持久化的一部分状态。通过blacklist 属性,我们可以指定哪一部分状态不要持久化,而whitelist 属性则相反,指定哪一部分状态要持久化。

例如,假设我们有以下的还原器。

const rootReducer = combineReducers({ 
  user: userReducer,
  notes: notesReducer
})

如果我们想阻止notes 的持久化,那么config 对象应该是如下样子。

const rootPersistConfig = {
  key: 'root',
  storage,
  blacklist: ['notes']
}

// OR

const rootPersistConfig = {
  key: 'root',
  storage,
  whitelist: ['users']
}

blacklistwhitelist 属性接受一个字符串数组。每个字符串必须与我们传递给persistReducer 的还原器所管理的状态的一部分相匹配。当使用blacklistwhitelist 时,我们只能针对一个级别的深度。但是,如果我们想针对上面某个状态中的一个属性,我们可以利用嵌套的坚持。

例如,假设userReducer 的初始状态看起来像下面这样。

const initialState = {
  user: {},
  isLoggedIn: false,
}

如果我们想阻止isLoggedIn 的持久化,我们的代码将如下所示。

const rootPersistConfig = {
  key: 'root',
  storage,
}

const userPersistConfig = {
  key: 'user',
  storage,
  blacklist: ['isLoggedIn']
}

const rootReducer = combineReducers({
  user: persistReducer(userPersistConfig, userReducer),
  notes: notesReducer
})

const persistedReducer = persistReducer(rootPersistConfig, rootReducer);

现在,isLoggedIn 属性就不会被持久化了。

总结

在本教程中,我们已经学会了如何使用Redux Toolkit中的Redux Persist来将我们的数据保存在持久化存储中。因此,即使在浏览器刷新后,我们的数据仍会保留。我们还探索了自定义Redux Persist的几个选项,例如,指定使用哪个存储引擎,以及使用blacklistwhitelist 属性自定义我们的状态中持久化的内容。

虽然在写这篇文章的时候,Redux Persist正在维护中,已经有一段时间没有更新了,但它仍然是一个拥有强大社区支持的伟大工具。我希望你喜欢这个教程,如果你有任何问题,请务必留下评论。

The postPersist state with Redux Persist using Redux Toolkit in Reactappeared first onLogRocket Blog.