当前位置 : 主页 > 网络编程 > JavaScript >

redux持久化之redux-persist结合immutable使用问题

来源:互联网 收集:自由互联 发布时间:2023-02-08
目录 前言 redux-persist 安装 使用到项目上 store.js index.js persist_reducer.js immutable 安装 使用到项目上 count_reducer.js 函数组件 类组件 结合使用存在的问题 组件 persist-reducer.js 解决 组件 persi
目录
  • 前言
  • redux-persist
    • 安装
    • 使用到项目上
      • store.js
      • index.js
      • persist_reducer.js
  • immutable
    • 安装
      • 使用到项目上
        • count_reducer.js
      • 函数组件
        • 类组件
        • 结合使用存在的问题
          • 组件
            • persist-reducer.js
            • 解决
              • 组件
                • persist-reducer.js
                  • 解决思路

                  前言

                  最近学习了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的资料请关注易盾网络其它相关文章!

                  上一篇:ECMAScript&nbsp;6对象的扩展实现示例
                  下一篇:没有了
                  网友评论