在redux中使用Immutable

1、什么是Immutable?

  Immutable是一旦创建,就不能被更改的数据。

  对Immutable对象的任何修改或添加删除操作都会返回一个新的Immutable对象。

  Immutable实现的原理是:Persistent Data Structure(持久化数据结构),

               也就是数据改变时(增删改)要保证旧数据同时可用且不变

  为了避免深拷贝把所有节点都复制一遍带来的性能损耗,Immutable使用了Structural Sharing(结构共享)

               即如果对象树节点发生变化,只修改这个结点和受它影响的父节点,其他节点共享


2、immutable常用API

//Map()  原生object转Map对象 (只会转换第一层,注意和fromJS区别)
immutable.Map({name:'danny', age:18})
//List() 原生array转List对象 (只会转换第一层,注意和fromJS区别)
immutable.List([1,2,3,4,5])
//fromJS() 原生js转immutable对象 (深度转换,会将内部嵌套的对象和数组全部转成immutable)
immutable.fromJS([1,2,3,4,5]) //将原生array --> List
immutable.fromJS({name:'danny', age:18}) //将原生object --> Map
//toJS() immutable对象转原生js (深度转换,会将内部嵌套的Map和List全部转换成原生js)
immutableData.toJS();
//查看List或者map大小
immutableData.size 或者 immutableData.count()
// is() 判断两个immutable对象是否相等
immutable.is(imA, imB);
//merge() 对象合并
var imA = immutable.fromJS({a:1,b:2});
var imA = immutable.fromJS({c:3});
var imC = imA.merge(imB);
console.log(imC.toJS()) //{a:1,b:2,c:3}
//增删改查(所有操作都会返回新的值,不会修改原来值)
var immutableData = immutable.fromJS({
a:1,
b:2,
c:{
d:3
}
});
var data1 = immutableData.get('a') // data1 = 1
var data2 = immutableData.getIn(['c', 'd']) // data2 = 3 getIn用于深层结构访问
var data3 = immutableData.set('a' , 2); // data3中的 a = 2
var data4 = immutableData.setIn(['c', 'd'], 4); //data4中的 d = 4
var data5 = immutableData.update('a',function(x){return x+4}) //data5中的 a = 5
var data6 = immutableData.updateIn(['c', 'd'],function(x){return x+4}) //data6中的 d = 7
var data7 = immutableData.delete('a') //data7中的 a 不存在
var data8 = immutableData.deleteIn(['c', 'd']) //data8中的 d 不存在

3、immutable可以让代码更简洁、提高性能、让redux更快更方便更安全

  在redux中每个reducer都返回一个新的对象(数组),常常会看到这样的代码:

// reducer
...
return [
...oldArr.slice(0,3),
newValue,
...oldArr.slice(4)
];

  

  为了返回新的对象(数组),不得不有上面奇怪的样子,

  而在使用更深的数据结构时会变的更棘手。

  让我们看看Immutable的做法:

// reducer
...
return oldArr.set(4, newValue);

  Immutable使用了Structure Sharing会尽量复用内存,

  甚至以前使用的对象也可以再次被复用,

  未引用的对象会被垃圾回收。


4、immutable使用过程中的一些注意点

a、fromJS和toJS会深度转换数据,随之带来的开销较大,尽可能避免使用,单层数据转换使用Map()和List()

b、js是弱类型,但Map类型的key必须是string!(也就是我们取值是要用get('1')而不是get(1))

c、所有针对immutable变量的增删改必须左边有赋值,因为所有操作都不会改变原来的值,只是生成一个新的变量

d、获取深层深套对象的值时不需要做每一层级的判空(JS中如果不判空会报错,immutable中只会给undefined)

e、immutable对象直接可以转JSON.stringify(),不需要显式手动调用toJS()转原生

f、判断对象是否是空可以直接用size

g、调试过程中要看一个immutable变量中真实的值,可以chrome中加断点,在console中使用.toJS()方法来查看

5、在react中使用immutable

  react做性能优化时,可以使用shouldComponentUpdate(),

  因为无论子组件用没用到父组件的参数只要父组件重新渲染了,

  子组件就会重新渲染

  而shouldComponentUpdate()很好地帮我们解决了这个问题,

//在render函数调用前判断:如果前后state中Number不变,通过return false阻止render调用
shouldComponentUpdate(nextProps,nextState){
if(nextState.Number == this.state.Number){
return false
}
}

  通过这个钩子我们可以很巧妙地避免了很多组件的重新渲染这种浪费性能的行为。

  但是这个钩子默认返回true,也就是说它默认是都重新渲染的,

  那么就需要多次使用,

  而我们在使用原生属性的时候,为了得出是true还是false

  不得不使用deepCopy、deepCompare,

  而这两种方法非常消耗性能

  而在有了Immutable之后,

  Immutable 则提供了简洁高效的判断数据是否变化的方法,

  来减少 React 重复渲染,提高性能,只需 === 和 is 比较就能知道是否需要执行 render()

  而这个操作几乎 0 成本,所以可以极大提高性能。

  修改后的 shouldComponentUpdate 是这样的:

import { is } from 'immutable';

shouldComponentUpdate: (nextProps = {}, nextState = {}) => {
const thisProps = this.props || {}, thisState = this.state || {}; //判断长度是否改变,长度改变的话,数据一定改一定需要重新渲染
if (Object.keys(thisProps).length !== Object.keys(nextProps).length ||
Object.keys(thisState).length !== Object.keys(nextState).length) {
return true;
} //当原数据和next的数据长度一致时需要遍历循环比较
for (const key in nextProps) {
if (!is(thisProps[key], nextProps[key])) {
return true;
}
} for (const key in nextState) {
if (thisState[key] !== nextState[key] || !is(thisState[key], nextState[key])) {
return true;
}
}
return false;
}

6、redux中应用immutable的小demo

  a、我的demo大概是这样

  b、store文件夹下的index.js中引入immutable

import { createStore, applyMiddleware } from 'redux'

//引入immutable
import Immutable from 'immutable' import thunk from 'redux-thunk'
import reducers from './reducers' //变为map函数
const initialState = Immutable.Map(); //注入
const store = createStore(reducers, initialState, applyMiddleware(thunk)) export default store

  c、store文件夹下的reducers.js中修改联合reducer的方法

//以前引入的是redux的combineReducers方法
// import { combineReducers } from 'redux' //现在改为引入redux-immutable中
import { combineReducers } from 'redux-immutable' import { reducer as cookbook } from 'pages/cookbook'
import { reducer as menu } from 'pages/menu' export default combineReducers({
cookbook,
menu
})

  d、在actionType.js和actionCreator.js中无变化,仍是定义变量和获取数据

  e、在页面的reducer.js中

import { CHANGE_FROM } from './actionTypes'

//引入fromJS
import { fromJS } from 'immutable' //把获取到的数据变成immutable的Map()形式
const defaultState = fromJS({
from: 'category'
}) //对state进行改变的时候采用immutable的方法
export default (state=defaultState, action) => {
if (action.type === CHANGE_FROM) {
return state.set('from', action.from)
} return state
}

  f、在页面使用的时候转化成原生使用

//通过toJS()方法转换为原生再进行map遍历
let data = this.props.categories && this.props.categories.get('热门').toJS().slice(0, 11).map((value, index) => {
return {
icon: value.img,
text: value.title
}
})

以上。

在react/redux中使用Immutable的更多相关文章

  1. Immutable.js 以及在 react+redux 项目中的实践

    来自一位美团大牛的分享,相信可以帮助到你. 原文链接:https://juejin.im/post/5948985ea0bb9f006bed7472?utm_source=tuicool&ut ...

  2. 清晰理解redux中的

    首先需要明白 Redux 的单一状态树的概念,所谓的单一状态树,就是指“所有的 state 都以一个对象树的形式储存在一个单一的 store 中.” 比如我们有这么一个状态树(或者你叫它状态对象也行) ...

  3. immutable.js 在React、Redux中的实践以及常用API简介

    immutable.js 在React.Redux中的实践以及常用API简介 学习下 这个immutable Data 是什么鬼,有什么优点,好处等等 mark :  https://yq.aliyu ...

  4. 在 react 项目里如何配合immutable在redux中使用

    一.reducer文件的处理 先安装 immutable 与 redux-immutable yarn add immutable redux-immutable 我们可能会在很多地方定义子树,这就需 ...

  5. react脚手架改造(react/react-router/redux/eslint/karam/immutable/es6/webpack/Redux DevTools)

    公司突然组织需要重新搭建一个基于node的论坛系统,前端采用react,上网找了一些脚手架,或多或少不能满足自己的需求,最终在基于YeoMan的react脚手架generator-react-webp ...

  6. 在 React Native 中使用 Redux 架构

    前言 Redux 架构是 Flux 架构的一个变形,相对于 Flux,Redux 的复杂性相对较低,而且最为巧妙的是 React 应用可以看成由一个根组件连接着许多大大小小的组件的应用,Redux 也 ...

  7. 在react项目中使用redux-thunk,react-redux,redux;使用总结

    先看是什么,再看怎么用: redux-thunk是一个redux的中间件,用来处理redux中的复杂逻辑,比如异步请求: redux-thunk中间件可以让action创建函数先不返回一个action ...

  8. 如何在非 React 项目中使用 Redux

    本文作者:胡子大哈 原文链接:https://scriptoj.com/topic/178/如何在非-react-项目中使用-redux 转载请注明出处,保留原文链接和作者信息. 目录 1.前言 2. ...

  9. 如何优雅地在React项目中使用Redux

    前言 或许你当前的项目还没有到应用Redux的程度,但提前了解一下也没有坏处,本文不会安利大家使用Redux 概念 首先我们会用到哪些框架和工具呢? React UI框架 Redux 状态管理工具,与 ...

随机推荐

  1. MySql 创建索引原则

    https://blog.csdn.net/csdnones/article/details/50412603 为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索引 ...

  2. Ch02 控制结构和函数 - 练习

    1. 一个数字如果为正数,则它的signum为1:如果是负数,则signum为-1:如果是0,则signum为0.编写一个函数来计算这个值. scala> def signum(x:Int):I ...

  3. 细说@Html.ActionLink()的用法

    一.@Html.ActionLink()概述 在MVC的Rasor视图引擎中,微软采用一种全新的方式来表示从前的超链接方式,它代替了从前的繁杂的超链接标签,让代码看起来更加简洁.通过浏览器依然会解析成 ...

  4. 记mysql中时间相关的一个奇怪问题

    发现mysql中类型为时间的字段,在查询时显示的时间是什么是依赖于客户端的,不同的客户端查同一个时间,可能在客户端显示的时间是不一样的.至于这个在哪里配置,以及服务端如何依据这个配置为客户端返回结果, ...

  5. IP地址和子网划分学习笔记之《IP地址详解》

    2018-05-03 18:47:37   在学习IP地址和子网划分前,必须对进制计数有一定了解,尤其是二进制和十进制之间的相互转换,对于我们掌握IP地址和子网的划分非常有帮助,可参看如下目录详文. ...

  6. c# 结构的使用

    类的定义的是引用类型,重点在堆上创建,有的时候类只包含极少的数据,因为管理堆而造成的开销是很大的.这时候更好的做法就是将类型定义成结构.结构是值类型,在栈上存储,能有效的减小内存管理的开销.c#基元类 ...

  7. mysql 分组取最新的一条记录(整条记录)

    方法:mysql取分组后最新的一条记录,下面两种方法.一种是先筛选 出最大和最新的时间,在连表查询.一种是先排序,然后在次分组查询(默认第一条),就是最新的一条数据了  #select * from ...

  8. TLS握手、中断恢复与证书中心的原因

    在双方都拿到随机数A.B.C后,将会使用这三个随机数生成一个对话密钥,然后使用该对话密钥进行对称加密通信,这种方式我们可以看到,安全性取决于随机数C的加密,前面的几个都是明文传的,这里就取决于服务器的 ...

  9. web api使用JObject接收时,报“无法创建抽象类”错误

    https://bbs.csdn.net/topics/391952288 在下列函数中增加  ModelBinders.Binders.Add(typeof(JObject), new JObjec ...

  10. 每天一个Linux命令 10

    文件处理命令:ln命令名称:ln 命令英文原意:link语法: ln -s [原文件] [目标文件] -s 创建软连接功能描述:生成链接文件 #ln -s /etc/issue /tmp/issue. ...