1、前言

本文章项目的依赖包及其版本如下:

Package NameVersion
antd^3.16.6
connected-react-router^6.4.0
customize-cra^0.2.12
immutable^4.0.0-rc.12
react^16.8.6
react-app-rewired^2.1.1
react-redux^7.0.3
react-router-config^5.0.0
react-router-dom^5.0.0
react-scripts3.0.1
redux^4.0.1
redux-logger^3.0.6
redux-persist^5.10.0
redux-persist-expire^1.0.2
redux-persist-transform-immutable^5.0.0
redux-saga^1.0.2

2、准备工作,搭建项目

下面是我的项目结构,每个人或者每个公司都有自己的目录架构,这里我的只供大家参考,另外搭建项目过程和介绍如何使用immutable.js不是本文章的重点,如何使用immutable.js以及本文章相关代码后面我会给出,如果有疑问欢迎大家在下面留言

|-- App.js|-- index.js|-- serviceWorker.js|-- assets|   |-- audio|   |-- css|   |   |-- App.scss|   |   |-- base.scss|   |   |-- index.css|   |   |-- override-antd.scss|   |-- image|   |   |-- Welcome.png|   |   |-- awbeci.png|   |   |-- bgLogo.png|   |   |-- hiy_logo.png|   |   |-- indexPop1.png|   |   |-- indexPop2.png|   |   |-- logo.png|   |   |-- logoX.png|   |   |-- right.png|   |-- video|-- components|   |-- HOC|   |   |-- loading.js|   |-- common|   |-- layout|       |-- AppRoute.js|       |-- LayoutPage.js|       |-- Loading.js|       |-- MasterPage.js|       |-- RouterView.js|       |-- SideMenu.js|       |-- layoutPage.scss|       |-- masterPage.scss|-- config|   |-- base.conf.js|-- context|   |-- themeContext.js|-- pages|   |-- DepartmentManage.js|   |-- Index.js|   |-- NoFound.js|   |-- NoPermission.js|   |-- UserManage.js|   |-- login|       |-- Login.js|       |-- login.scss|-- redux|   |-- actions|   |   |-- authAction.js|   |   |-- layoutPageAction.js|   |-- middleware|   |   |-- authTokenMiddleware.js|   |-- reducers|   |   |-- authReducer.js|   |   |-- index.js|   |   |-- layoutPageReducer.js|   |-- sagas|   |   |-- authSaga.js|   |   |-- index.js|   |-- store|   |   |-- index.js|   |-- thunks|-- router|   |-- index.js|-- service|   |-- apis|   |   |-- 1.0|   |       |-- index.js|   |       |-- urls.js|   |-- mocks|   |   |-- 1.0|   |       |-- index.js|   |       |-- testMock.js|   |-- request|       |-- ApiRequest.js|       |-- MockRequest.js|-- test|   |-- App.test.js|-- utils

3、集成immutable.js

此项目除了依赖包要配置之外,只有redux下的reducer相关文件会设置成immutable.js普通的react组件我没有设置成immutable.js

App.js

import { ConnectedRouter } from "connected-react-router";//换成import { ConnectedRouter } from "connected-react-router/immutable";

store->index.js

import { routerMiddleware } from "connected-react-router";//换成import { routerMiddleware } from "connected-react-router/immutable";//添加import immutableTransform from "redux-persist-transform-immutable";const persistConfig = {  transforms: [encryptor],  //换成  transforms: [    immutableTransform()    // 注意:必须要注释encryptor否则会报错    // encryptor  ],  ...}

redux->reducers->index.js

import { connectRouter } from "connected-react-router";//换成import { connectRouter } from "connected-react-router/immutable";

redux->reducers->authReducer.js

//添加import { Map, fromJS, merge } from "immutable";const initState = {  user: null,  token: ""};[authTypes.AUTH_SUCCESS]: (state, action) => {      return Object.assign({}, state, { user: action.data.user, token: action.data.token });    },    [authTypes.SIGN_OUT]: (state, action) => {      return Object.assign({}, state, {        user: null,        token: ""      });    }//换成const initState = fromJS({  user: null,  token: ""});    [authTypes.AUTH_SUCCESS]: (state, action) => {      return state.merge({        user: action.data.user,        token: action.data.token      });    },    [authTypes.SIGN_OUT]: (state, action) => {      return state.merge({        user: null,        token: ""      });    }

redux->reducers->layoutPageReducer.js

//添加import { Map, fromJS, merge, List } from "immutable";const initState = {  index: "126",  subIndex: "",  collapsed: false,  menus: [],  loading: false};[layoutPageTypes.SAVE_MENU_INDEX]: (state, action) => {      const { keyPath } = action.payload;      let index = keyPath[0];      let subIndex = null;      if (keyPath.length === 2) {        subIndex = keyPath[1];      }      return Object.assign({}, state, {        index: index,        subIndex: subIndex      });    },    [layoutPageTypes.SAVE_MENU_COLLAPSED]: (state, action) => {      const { collapsed } = action.payload;      return Object.assign({}, state, {        collapsed: collapsed      });    },    [layoutPageTypes.GET_MENUS]: (state, action) => {      const { menus } = action;      return Object.assign({}, state, {        menus: menus      });    }//换成const initState = fromJS({  index: "126",  subIndex: "",  collapsed: false,  menus: List()});[layoutPageTypes.SAVE_MENU_INDEX]: (state, action) => {      const { keyPath } = action.payload;      let index = keyPath[0];      let subIndex = null;      if (keyPath.length === 2) {        subIndex = keyPath[1];      }      return state.merge({        index: index,        subIndex: subIndex      });    },    [layoutPageTypes.SAVE_MENU_COLLAPSED]: (state, action) => {      const { collapsed } = action.payload;      return state.merge({        collapsed: collapsed      });    },    [layoutPageTypes.GET_MENUS]: (state, action) => {      const { menus } = action;      return state.merge({        menus: menus      });    }

middleware->authTokenMiddleware.js

//添加import { fromJS } from "immutable";if (action.type === REHYDRATE) {    if (action.payload && action.payload.authReducer && action.payload.authReducer.token) {      ApiRequest.setToken(action.payload.authReducer.token);    }  }//换成if (action.type === REHYDRATE) {    if (typeof action.payload !== "undefined") {      let authReducer = action.payload.authReducer;      if (authReducer) {        const token = authReducer.get("token");        ApiRequest.setToken(token ? token : null);      }    }  }

components->layout->LayoutPage.js

<span style={{ marginLeft: 8 }}>{authReducer.user ? authReducer.user.name : "用户"}</span><Switch>{authReducer.token ? renderRoutes(routes) : <Redirect to="/login" />}</Switch>//换成<span style={{ marginLeft: 8 }}>{authReducer.get("user") ? authReducer.getIn(["user", "name"]) : "用户"}</span><Switch>{authReducer.get("token") ? renderRoutes(routes) : <Redirect to="/login" />}</Switch>

components->layout->SideMenu.js

let menus = layoutPageReducer.menus;<Menu          theme="light"          defaultSelectedKeys={[layoutPageReducer.index]}          selectedKeys={[layoutPageReducer.index]}          defaultOpenKeys={[layoutPageReducer.subIndex]}          mode="inline"          className="sider-menu-container"          inlineCollapsed={layoutPageReducer.collapsed}          onClick={this.clickSidebarMenu}        >          {newMenus}        </Menu>//换成let menus = layoutPageReducer.get("menus");        <Menu          theme="light"          defaultSelectedKeys={[layoutPageReducer.get("index")]}          selectedKeys={[layoutPageReducer.get("index")]}          defaultOpenKeys={[layoutPageReducer.get("subIndex")]}          mode="inline"          className="sider-menu-container"          inlineCollapsed={layoutPageReducer.get("collapsed")}          onClick={this.clickSidebarMenu}        >          {newMenus}        </Menu>

components->layout->AppRoute.js

Authentication() {    return this.props.store.authReducer.token ? <Redirect to="/" /> : <Login />;  }//换成    return this.props.store.authReducer.get("token") ? <Redirect to="/" /> : <Login />;

4、启动项目看是否集成成功

命令行运行:yarn start

清除下缓存尤其是localstorage,如果看到上面的登录页面那么恭喜你配置成功!

5、redux-logger 打印immutable.js日志

下面我们来看看redux-logger打印的日志跟我们不使用immutable.js有什么区别?

如上图所示,打印的日志数据就是immutable.js的相关数据,但是我们会发现阅读性不是太好,这里我们安装一个格式化immutable.js的日志数据的Chrome插件,安装一下即可,之前我有写过一篇文章教你怎么使用这个插件,点击跳转阅读,安装好之后,我们再来查看数据,如下所示:

是不是增加了日志的可阅读性,到此我们集成Immutable.js就至此结束,欢迎大家在下面留言交流!

6、总结

1)上面是教你如何把现有项目集成immutable.js,如果你是新项目,上面有些配置其实是不用管的;
2)上面的集成原则:把原生的写法改成immutable.js的写法即可!;
3)这里我用到了redux-persist,如果你没有用到这个包,那么你就可以不用安装redux-persist-transform-immutable,换成redux-immutable包即可,具体如何操作,官方文档上面有讲,这里就不多说了。
4)演示地址、本文章代码,另外本文章代码对应github上面的immutable.js分支,而演示地址对应的是master分支!

7、引用

1.Immutable.js了解一下?
2.React引用数据类型与immutable.js的使用实例
3.react 使用的小建议
4.Immutable.js 以及在 react+redux 项目中的实践
5.React Native Redux、redux-persist、immutable.js 结合实践
6.Error when using redux-persist with redux-immutable
7.大话immutable.js
8.Immutable.js 以及在 react+redux 项目中的实践
9.Immutable.js与React,Redux及reselect的实践
10.如何用React+Redux+ImmutableJS进行SPA开发
11.immutable.js 在React、Redux中的实践以及常用API简介
12.笔记, immutable-js 基础操作
13.Immutable.js 到底值不值得用?
14.Immutable 详解及 React 中实践
15.Immutable.js与React,Redux及reselect的实践