前言

最近学习了redux以及react-redux的结合使用确实让redux在react中更好的输出代码啦~

但是考虑到项目的各种需求,我们还是需要对redux进行深一步的改造,让其能更好的满足我们的日常开发,大大提高我们的开发效率。

今天给大家推荐两个好用的功能包,并解决一个它们结合使用存在的问题。

redux-persist

redux-persist 主要用于帮助我们实现redux的状态持久化

所谓状态持久化就是将状态与本地存储联系起来,达到刷新或者关闭重新打开后依然能得到保存的状态。

安装

yarn add redux-persist 
// 或者
npm i redux-persist

Github 地址 https://github.com/rt2zz/redux-persist

大家可以去看看官方的说明文档,这里就不一一介绍功能了,简单讲一点常用功能和导入到项目使用。

使用到项目上

store.js

带有 // ** 标识注释的就是需要安装后添加进去使用的一些配置,大家好好对比下投掷哦

下面文件也是一样

import { createStore, applyMiddleware, compose } from "redux";
import thunk from 'redux-thunk'
import { persistStore, persistReducer } from 'redux-persist' // **
import storage from 'redux-persist/lib/storage' // **
import reducer from './reducer'
const persistConfig = {  // **
    key: 'root',// 储存的标识名
    storage, // 储存方式
    whitelist: ['persistReducer'] //白名单 模块参与缓存
}
const persistedReducer = persistReducer(persistConfig, reducer) // **
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(persistedReducer, composeEnhancers(applyMiddleware(thunk))) // **
const persistor = persistStore(store) // **
export { // **
    store,
    persistor
}

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import { PersistGate } from 'redux-persist/integration/react' // **
import { store, persistor } from './store' // **
import 'antd/dist/antd.min.css';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}> 
    {/*  使用PersistGate //**   */}
      <PersistGate loading={null} persistor={persistor}>
        <BrowserRouter>
          <App />
        </BrowserRouter>
      </PersistGate>
    </Provider>
  </React.StrictMode>
);

persist_reducer.js

注意此时的模块是在白名单之内,这样persist_reducer的状态就会进行持久化处理了

import { DECREMENT } from './constant'
const defaultState = ({
    count: 1000,
    title: 'redux 持久化测试'
})
const reducer = (preState = defaultState, actions) => {
    const { type, count } = actions
    switch (type) {
        case DECREMENT:
             return { ...preState, count: preState.count - count * 1 }
        default:
            return preState
    }
}
export default reducer

这样就可以使用起来了,更多的配置可以看看上面Github的地址上的说明文档

immutable

immutable 主要配合我们redux的状态来使用,因为reducer必须保证是一个纯函数,所以我们当状态中有引用类型的值时我们可能进行浅拷贝来处理,或者遇到深层次的引用类型嵌套时我们采用深拷贝来处理。

但是我们会觉得这样的处理确实稍微麻烦,而且我们若是采用简单的深拷贝 JSON.parse JSON.stringify 来处理也是不靠谱的,存在缺陷 就比如属性值为undefined 时会忽略该属性。

所以 immutable 就是来帮我们解决这些问题,使用它修改后会到的一个新的引用地址,且它并不是完全复制的,它会尽可能的利用到未修改的引用地址来进行复用,比起传统的深拷贝性能确实好很多。

这里就不多说了,想要了解更多可以看看下面的GitHub官网说明文档。

安装

npm install immutable
// 或者
yarn add immutable

GitHub地址 https://github.com/immutable-js/immutable-js

使用到项目上

count_reducer.js

import { INCREMENT } from './constant'
import { Map } from 'immutable'
// 简单的结构用Map就行 复杂使用fromJs 读取和设置都可以getIn setIn ...
const defaultState = Map({ // **
    count: 0,
    title: '计算求和案例'
})
const reducer = (preState = defaultState, actions) => {
    const { type, count } = actions
    switch (type) {
        case INCREMENT:
            // return { ...preState, count: preState.count   count * 1 }
            return preState.set('count', preState.get('count')   count * 1) // **
        default:
            return preState
    }
}
export default reducer

读取和派发如下 : 派发无需变化,就是取值时需要get

函数组件

    const dispatch = useDispatch()
    const { count, title } = useSelector(state => ({
        count: state.countReducer.get("count"),
        title: state.countReducer.get("title")
    }), shallowEqual)
    const handleAdd = () => {
        const { value } = inputRef.current
        dispatch(incrementAction(value))
    }
    const handleAddAsync = () => {
        const { value } = inputRef.current
        dispatch(incrementAsyncAction(value, 2000))
    }

类组件

class RedexTest extends Component {
    // ....略
    render() {
        const { count, title } = this.props
        return (
            <div>
                <h2>Redux-test:{title}</h2>
                <h3>count:{count}</h3>
                <input type="text" ref={r => this.inputRef = r} />
                <button onClick={this.handleAdd}>   </button>
                <button onClick={this.handleAddAsync}>asyncAdd</button>
            </div>
        )
    }
}
//使用connect()()创建并暴露一个Count的容器组件
export default connect(
    state => ({
        count: state.countReducer.get('count'),
        title: state.countReducer.get('title')
    }),
    {
        incrementAdd: incrementAction,
        incrementAsyncAdd: incrementAsyncAction
    }
)(RedexTest)

这样就可以使用起来了,更多的配置可以看看上面Github的地址上的说明文档

结合使用存在的问题

结合使用有一个坑!!!

是这样的,当我们使用了redux-persist 它会每次对我们的状态保存到本地并返回给我们,但是如果使用了immutable进行处理,把默认状态改成一种它内部定制Map结构,此时我们再传给 redux-persist,它倒是不挑食能解析,但是它返回的结构变了,不再是之前那个Map结构了而是普通的对象,所以此时我们再在reducer操作它时就报错了

如下案例:

组件

import React, { memo } from "react";
import { useDispatch, useSelector, shallowEqual } from "react-redux";
import { incrementAdd } from "../store/persist_action";
const ReduxPersist = memo(() => {
  const dispatch = useDispatch();
  const { count, title } = useSelector(
    ({ persistReducer }) => ({
      count: persistReducer.get("count"),
      title: persistReducer.get("title"),
    }),
    shallowEqual
  );
  return (
    <div>
      <h2>ReduxPersist----{title}</h2>
      <h3>count:{count}</h3>
      <button onClick={(e) => dispatch(incrementAdd(10))}>-10</button>
    </div>
  );
});
export default ReduxPersist;

persist-reducer.js

import { DECREMENT } from './constant'
import { fromJS } from 'immutable'
const defaultState = fromJS({
    count: 1000,
    title: 'redux 持久化测试'
})
const reducer = (preState = defaultState, actions) =&gt; {
    const { type, count } = actions
    switch (type) {
        case DECREMENT:
            return preState.set('count', preState.get('count') - count * 1)
        default:
            return preState
    }
}
export default reducer

按理说是正常显示,但是呢由于该reducer是被redux-persist处理的,所以呢就报错了

报错提示我们没有这个 get 方法了,即表示变成了普通对象

解决

组件

import React, { memo } from "react";
import { useDispatch, useSelector, shallowEqual } from "react-redux";
import { incrementAdd } from "../store/persist_action";
const ReduxPersist = memo(() => {
  const dispatch = useDispatch();
  // **
  const { count, title } = useSelector(
    ({ persistReducer: { count, title } }) => ({
      count,
      title,
    }),
    shallowEqual
  );
  //const { count, title } = useSelector(
  //  ({ persistReducer }) => ({
  //   count: persistReducer.get("count"),
  //    title: persistReducer.get("title"),
  //  }),
  //  shallowEqual
  // );
  return (
    <div>
      <h2>ReduxPersist----{title}</h2>
      <h3>count:{count}</h3>
      <button onClick={(e) => dispatch(incrementAdd(10))}>-10</button>
    </div>
  );
});
export default ReduxPersist;

persist-reducer.js

import { DECREMENT } from './constant'
import { fromJS } from 'immutable'
const defaultState = ({ // **
    count: 1000,
    title: 'redux 持久化测试'
})
const reducer = (preState = defaultState, actions) => {
    const { type, count } = actions
    let mapObj = fromJS(preState) // **
    switch (type) {
        case DECREMENT:
            // return preState.set('count', preState.get('count') - count * 1) 
            return mapObj.set('count', mapObj.get('count') - count * 1).toJS() // **
        default:
            return preState
    }
}
export default reducer

解决思路

由于 redux-persist 处理每次会返回普通对象,所以我们只能等要在reducer中处理状态时,我们先将其用immutable处理成它内部定制Map结构,然后我们再进行set操作修改,最后我们又将Map结构转换为普通对象输出,这样就完美的解决了这个问题。

以上就是redux持久化之redux-persist结合immutable使用问题的详细内容,更多关于redux持久化redux-persist的资料请关注Devmax其它相关文章!

redux持久化之redux-persist结合immutable使用问题的更多相关文章

  1. ios – 使用react-native-router-flux和redux,如何更新视图组件中的状态?

    为了完整起见,整个代码可以在github找到.解决方法您可能忘记将Launch组件连接到商店.你想要做的是类似于你在ExampleContainer中所做的,即然后正确的值将显示在您的日志中

  2. ios – AFNetworking自动持久化Cookie

    在ThisQuestion中说,AFNetworking在后台自动处理cookies,但是在Previous问题中,我遇到麻烦,在登录时在PHP服务器上保持会话.一旦关闭的应用程序,并回到会议已经没了.答案是保持像这样的cookie来解决问题:当我尝试做这样的事情时,这给我一个应用程序崩溃.当我登录时,我设置了NSUserDefault:这是错误的使用方法吗?谢谢.解决方法使用以下内容,这是保存和加载适用于我的Cookie的正确方法:希望有帮助!

  3. Spring Boot日志的打印与持久化详细解析

    Spring Boot默认使用SLF4J+Logback 记录日志,并提供了默认配置,即使我们不进行任何额外配,也可以使用SLF4J+Logback进行日志输出

  4. 详解React 和 Redux的关系

    这篇文章主要为大家介绍了React 和 Redux的关系,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

  5. redux功能强大的Middleware中间件使用学习

    这篇文章主要为大家介绍了redux功能强大的Middleware中间件使用学习,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  6. Flutter持久化存储之数据库存储(sqflite)详解

    这篇文章主要给大家介绍了关于Flutter持久化存储之数据库存储的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用Flutter具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

  7. Redux模块化拆分reducer函数流程介绍

    Reducer是个纯函数,即只要传入相同的参数,每次都应返回相同的结果。不要把和处理数据无关的代码放在Reducer里,让Reducer保持纯净,只是单纯地执行计算,这篇文章主要介绍了Redux拆分reducer函数流程

  8. Vue注册模块与登录状态的持久化实现方法详解

    这篇文章主要介绍了Vue注册模块与登录状态的持久化实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  9. React路由中的redux和redux知识点拓展

    这篇文章主要介绍了React路由中的redux和redux知识点拓展,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的朋友可以参考学习一下

  10. 一文教会你用redux实现computed计算属性

    在computed中,可以定义一些属性,即计算属性,下面这篇文章主要给大家介绍了关于如何利用redux实现computed计算属性的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部