导航
导航
文章目录󰁋
  1. 一、前言
  2. 二、什么是 Immutable Data
  3. 三、为什么要在React.js中使用Immutable
  4. 四、Immutable 的几种数据类型
  5. 五、几个重要的API
  6. 六、API
    1. 创建
    2. 判断是否是一个Map或者List
    3. 获取大小
    4. 添加元素
    5. List 特有的添加元素
    6. 删除元素
    7. 修改元素
    8. 获取某个元素值
    9. 查找某个元素
    10. List 特有查找某个元素
    11. 查找最大、最小元素
    12. 截取
    13. 循环遍历
    14. Map 特有 mapKeys() mapEntries()
    15. merge
    16. jonin() 转换为字符串
    17. isEmpty() 判空
    18. has() hasIn() 检查是否有某个key
    19. includes() 是否包含某些元素
    20. isSubset() 子集判断
    21. reverse() 反转
    22. 排序
    23. flatten() 平铺
    24. groupBy() 分组
    25. flip() Map 特有翻转
    26. 连接 concat()
    27. 类型转换
  7. 七、和React Redux 架构的结合
  8. 八、思维导图总结API
  9. 九、更多参考

关注作者公众号

和万千小伙伴一起学习

公众号:前端进价之旅

React之Immutable学习记录(十二)

整理于互联网

一、前言

从问题说起:熟悉 React 组件生命周期的话都知道:调用 setState 方法总是会触发 render 方法从而进行 vdom re-render 相关逻辑,哪怕实际上你没有更改到 Component.state

this.state = {count: 0}
this.setState({count: 0});// 组件 state 并未被改变,但仍会触发 render 方法
  • 为了避免这种性能上的浪费,React 提供了一个 shouldComponentUpdate 来控制触发 vdom re-render 逻辑的条件。于是 PureRenderMixin 作为一种优化技巧被使用。它仅仅是浅比较对象,深层次的数据结构根本不管用

js中的Immutable Data

javascript中我们可以通过deep clone来模拟Immutable Data,就是每次对数据进行操作,新对数据进行deep clone出一个新数据

  • deep clone
  • 当然你或许意识到了,这样非常的慢
'use strict';  
var cloneDeep = require('lodash.clonedeep');

var data = {
id: 'data',
author: {
name: 'mdemo',
github: 'https://github.com/demohi'
}
};

var data1 = cloneDeep(data);

console.log('equal:', data1===data); //false

data1.id = 'data1';
data1.author.name = 'demohi';

console.log(data.id);// data
console.log(data1.id);// data1

console.log(data.author.name);//mdemo
console.log(data1.author.name);//demohi

这时候 immutableJS 就派得上用场了

var map1 = Immutable.fromJS({a:1, b:1, c:{b:{c:{d:{e:7}}}}});
var map2 = Immutable.fromJS({a:1, b:1, c:{b:{c:{d:{e:7}}}}});
Immutable.is(map1, map2); // true
  • 遍历对象不再用for-in,可以这样:
Immutable.fromJS({a:1, b:2, c:3}).map(function(value, key) { /* do some thing */});

二、什么是 Immutable Data

  • Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象
  • Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变
  • 同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了 Structural Sharing····(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。

打印immutableJS看看有什么东西

一个说明不可变的例子

// 原生对象
let a1 = {
b: 1,
c: {
c1: 123
}
};

let b1 = a1;
b1.b = 2;

console.log(a1.b, b1.b); // 2, 2
console.log(a1 === b1); // true
console.log(a1.c === b1.c); // true

// immutable.js 的Map
let a2 = Immutable.fromJS({
b: 1,
c: {
c1: 123
}
});

let b2 = a2.set('b', 2);

// 对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象
console.log(a2.get('b'), b2.get('b')); // 1, 2 对象 a2 的 b 值并没有变成2。
console.log(a2 === b2); // false

//如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
console.log(a2.get('c') === b2.get('c')); //true

三、为什么要在React.js中使用Immutable

  • 它是一个完全独立的库,无论基于什么框架都可以用它。意义在于它弥补了Javascript 没有不可变数据结构的问题
  • 由于是不可变的,可以放心的对对象进行任意操作。在React开发中,频繁操作state对象或是store,配合immutableJS快、安全、方便
  • 熟悉React.js的都应该知道,React.js是一个UI = f(states)的框架,为了解决更新的问题,React.js使用了virtual domvirtual dom通过diff修改dom,来实现高效的dom更新。
  • 但是有一个问题。当state更新时,如果数据没变,你也会去做virtual domdiff,这就产生了浪费。这种情况其实很常见
  • 当然你可能会说,你可以使用PureRenderMixin来解决呀,PureRenderMixin是个好东西,我们可以用它来解决一部分的上述问题
  • PureRenderMixin只是简单的浅比较,不使用于多层比较。那怎么办?自己去做复杂比较的话,性能又会非常差
  • 方案就是使用immutable.js可以解决这个问题。因为每一次state更新只要有数据改变,那么PureRenderMixin可以立刻判断出数据改变,可以大大提升性能

Immutable 优点

  • Immutable 降低了 Mutable 带来的复杂度

可变(Mutable)数据耦合了 TimeValue 的概念,造成了数据很难被回溯

  • 节省内存

Immutable.js 使用了 Structure Sharing 会尽量复用内存,甚至以前使用的对象也可以再次被复用。没有被引用的对象会被垃圾回收

import { Map} from 'immutable';
let a = Map({
select: 'users',
filter: Map({ name: 'Cam' })
})
let b = a.set('select', 'people');

a === b; // false
a.get('filter') === b.get('filter'); // true
  • Undo/Redo,Copy/Paste,甚至时间旅行这些功能做起来小菜一碟

因为每次数据都是不一样的,只要把这些数据放到一个数组里储存起来,想回退到哪里就拿出对应数据即可,很容易开发出撤销重做这种功能。

  • 并发安全

传统的并发非常难做,因为要处理各种数据不一致问题,因此『聪明人』发明了各种锁来解决。但使用了 Immutable 之后,数据天生是不可变的,并发锁就不需要了。

  • 拥抱函数式编程

Immutable 本身就是函数式编程中的概念,纯函数式编程比面向对象更适用于前端开发。因为只要输入一致,输出必然一致,这样开发的组件更易于调试和组装。

Immutable 缺点

  • 需要学习新的 API
  • 增加了资源文件大小
  • 容易与原生对象混淆

四、Immutable 的几种数据类型

  • List: 有序索引集,类似JavaScript中的Array
  • Map: 无序索引集,类似JavaScript中的Object
  • OrderedMap: 有序的Map,根据数据的set()进行排序。
  • Set: 没有重复值的集合。
  • OrderedSet: 有序的Set,根据数据的add进行排序。
  • Stack: 有序集合,支持使用unshift()shift()添加和删除。
  • Range(): 返回一个Seq.Indexed类型的集合,这个方法有三个参数,start表示开始值,默认值为0end表示结束值,默认为无穷大,step代表每次增大的数值,默认为1.如果start = end,则返回空集合。
  • Repeat(): 返回一个vSeq.Indexe类型的集合,这个方法有两个参数,value代表需要重复的值,times代表要重复的次数,默认为无穷大。
  • Record: 一个用于生成Record实例的类。类似于JavaScriptObject,但是只接收特定字符串为key,具有默认值。
  • Seq: 序列,但是可能不能由具体的数据结构支持。
  • Collection: 是构建所有数据结构的基类,不可以直接构建

上面那么多常用的也就是 ListMap

五、几个重要的API

1、fromJS()

  • fromJS() 是最最最常用的将原生JS数据转换为ImmutableJS数据的转换方法。使用方式类似于 JSON.parse(),接收两个参数:json 数据和 reviver函数
  • 在不传递reviver函数的情况下,默认将原生JSArray转为ListObject转为Map
// 常见
const t1 = Immutable.fromJS({a: {b: [10, 20, 30]}, c: 40});
console.log(t1);

// 不常用
const t2 = Immutable.fromJS({a: {b: [10, 20, 30]}, c: 40}, function(key, value) {
// 定制转换方式,下这种就是将Array转换为List,Object转换为Map
const isIndexed = Immutable.Iterable.isIndexed(value);
return isIndexed ? value.toList() : value.toOrderedMap();
// true, "b", {b: [10, 20, 30]}
// false, "a", {a: {b: [10, 20, 30]}, c: 40}
// false, "", {"": {a: {b: [10, 20, 30]}, c: 40}}
});
console.log(t2);

2、is()

先来看官网的一段话: immutable数据应该被当作值而不是对象,值是表示该事件在特定时刻的状态。这个原则对理解不可变数据的适当使用是最重要的。为了将Immutable.js数据视为值,就必须使用Immutable.is()函数或.equals()方法来确定值相等,而不是确定对象引用标识的 === 操作符

  • 所以is()就是用来对两个immutable对象进行值比较的。使用方式类似于 Object.is(obj1, obj2),接收两个参数
const map1 = Immutable.Map({a:1, b:1, c:1});
const map2 = Immutable.Map({a:1, b:1, c:1});

// 两个不同的对象
console.log(map1 === map2); // false
// 进行值比较
console.log(Immutable.is(map1, map2)); // true

// 不仅仅只能比较ImmutableJS的类型的数据
console.log(Immutable.is(undefined, undefined)); // true
console.log(Immutable.is(null, undefined)); // false
console.log(Immutable.is(null, null)); // true
console.log(Immutable.is(NaN, NaN)); // true

// 区别于 Object.is
console.log(Object.is(0, -0) ,Immutable.is(-0, 0)); // false , true

3、Map

Map 数据类型,对应原生 Object 数组。最最常用的 数据结构之一,循环时无序(orderedMap有序),对象的 key 可以是任意值。具体看下面的例子

console.log(Map().set(List.of(1), 'list-of-one').get(List.of(1)));
console.log(Map().set(NaN, 'NaN').get(NaN));
console.log(Map().set(undefined, 'undefined').get(undefined));
console.log(Map().set(null, 'null').get(null));
  • 简单介绍 OrderedMap

OrderedMapMap 的变体,它除了具有 Map 的特性外,还具有顺序性,当开发者遍历 OrderedMap 的实例时,遍历顺序为该实例中元素的声明、添加顺序。OrderedMap比非有序Map更昂贵,并且可能消耗更多的内存。如果真要求遍历有序,请使用List

4、List

List 数据类型,对应原生 Array数组。和原生数组,最大区别不存在’空位’。[, , , , ]

console.log(List([,,,,]).toJS());// [undefined, undefined, undefined, undefined]

六、API

我们主要介绍MapList

创建

1、通过构造函数 Map()

构造函数不常用,一般都是通过Immutable.fromJS()将一个JS原生对象转换为一个Immutable对象

2、Map()

/*
Map<K, V>(): Map<K, V>
Map<K, V>(iter: Iterable.Keyed<K, V>): Map<K, V>
Map<K, V>(iter: Iterable<any, Array<any>>): Map<K, V>
Map<K, V>(obj: Array<Array<any>>): Map<K, V>
Map<V>(obj: {[key: string]: V}): Map<string, V>
Map<K, V>(iterator: Iterator<Array<any>>): Map<K, V>
Map<K, V>(iterable: Object): Map<K, V>
*/

console.log(Map().toJS()); // {}
console.log(Map({key: "value"}).toJS()); // {key: "value"}

同Key覆盖问题

//最后的{key: value2} 覆盖了前面的 {key: value}
console.log(Map([["key", "value"], ["key", "value2"], ["key1", "value1"]]).toJS());// {key: "value2", key1: "value1"}

3、List()

/*
List<T>(): List<T>
List<T>(iter: Iterable.Indexed<T>): List<T>
List<T>(iter: Iterable.Set<T>): List<T>
List<K, V>(iter: Iterable.Keyed<K, V>): List<any>
List<T>(array: Array<T>): List<T>
List<T>(iterator: Iterator<T>): List<T>
List<T>(iterable: Object): List<T>
*/

console.log(List().toJS()); // []
console.log(List([1,2,3,4,{a:123}]).toJS()); // [ 1, 2, 3, 4, {a: 123}]

4、另一种方式

Map.of()

console.log(Map.of('key1','value1','key2','value2','key3','value3').toJS()); // {key1: "value1", key2: "value2", key3: "value3"}

List.of()

console.log(List.of({x:1}, 2, [3], 4).toJS()); // [{x:1}, 2, [3], 4]

判断是否是一个Map或者List

1、Map判断

  • 判断是否是一个Map , 对原生Object不生效
console.log(Map.isMap({})); // false
console.log(Map.isMap(Map({}))); // true

2、List判断

判断是否是一个List , 对原生Array不生效

console.log(List.isList([])); // false
console.log(List.isList(List([]))); // true

获取大小

1、size

// list
console.log(List([1,2,3,4]).size);// 4
console.log(List.of(1, 2, 3, 4).size);// 4

// map
console.log(Map({key: "value2", key1: "value1"}).size);// 2
console.log(Map.of({x:1}, 2, [3], 4).size);// 2

count()

// map
console.log(Immutable.fromJS({key: "value2", key1: "value1"}).count());// 4
// 可以定制条件,来确定大小
console.log(Immutable.fromJS({key: 1, key1: 34}).count((value, key, obj) => {
return value > 3;
}));// 1 value大于3的有两个

// list
console.log(Immutable.fromJS([1, 2, 5, 6]).count());// 4
// 可以制定条件,来确定 大小
console.log(Immutable.fromJS([1, 2, 5, 6]).count((value, index, array) => {
return value > 3;
}));// 2 大于3的有两个

countBy()

countBy()count()的区别就是它的返回值是一个对象。

// Map
console.log(Immutable.fromJS({key: 1, key1: 34}).countBy((value, key, obj) => {
return value > 3;
}).toJS());// {false: 1, true: 1}

// list
console.log(Immutable.fromJS([1, 2, 5, 6]).countBy((value, index, array) => {
return value > 3;
}).toJS());// {false: 2, true: 2}

添加元素

1、Set

// Map
// 将 key 位置的元素替换为 value
const $obj1 = Map({a: {a1: 34}, b: 2, c: 3, d: 444});
console.log($obj1.set('a', 0).toJS()); // {a: 0, b: 2, c: 3, d: 444}
console.log($obj1.set('e', 99).toJS()); // {a: 1, b: 2, c: 3, d: 444, e: 99}

// List
// 将 index 位置的元素替换为 value,即使索引越界也是安全的, 空位 undefined
const $arr1 = List([1, 2, 3]);
console.log($arr1.set(-1, 0).toJS()); // [1, 2, 0] 注意-1 等效于 $arr1.set($arr1.size + -1, 0)
console.log($arr1.set(4, 0).toJS()); // [ 1, 2, 3, undefined, 0 ] 空位置为了undefined

2、setIn

// Map
console.log(Immutable.fromJS([1, 2, 3, {a: 45, b: 64}]).setIn(['3', 'a'], 1000).toJS());//[1, 2, 3, {a: 1000, b: 64}]

// List
console.log(Immutable.fromJS([1, 2, 3, {a: 45, b: 64}]).setIn(['3', 'a'], 1000).toJS());//[1, 2, 3, {a: 1000, b: 64}]

List 特有的添加元素

1、插入元素

// insert(index: number, value: T)
// 向 index 位置插入 value
console.log(Immutable.fromJS([1, 2, 3]).insert(1, 1.5).toJS()); // [ 1, 1.5, 2, 3 ]

2、设置size

  • 默认值undefined
console.log(List([]).setSize(2).toJS()); // [undefined, undefined]

3、pop、push、shift、unshift

List数据类型也拥有poppushshiftunshift这四种操作方法,和原生Array的四种方法使用方式一致,但唯一区别就是返回新的List,并且不改变原来的数组本身,而原生则是会改变元素本身

// ImmutableJS:返回新的List,并且不改变元素本身
const $test = List([1, 2, 3, 4]);
console.log($test.pop().toJS(), $test.toJS()); // [1, 2, 3] [1, 2, 3, 4]
// 原生:返回被改变的值,改变元素本身
const test = [1, 2, 3, 4];
console.log(test.pop(), test); // 4 [1, 2, 3]

4、花样插入

// interpose
// 插入xxx之间
console.log(Immutable.fromJS([1, 2, 5, 6]).interpose(5555).toJS()); // [1, 5555, 2, 5555, 5, 5555, 6]

// interleave
// 被操作的两个数组,每个的第一项、第二项、第三项... 组成新的数组。
console.log(Immutable.fromJS([1, 2, 5, 6]).interleave(Immutable.fromJS([555, 666])).toJS()); // [1, 555, 2, 666]

// zip
// 被操作的两个数组,抽离第一项和第二项组成新的子数组,放入到一个大数组中,形成二维数组。
console.log(Immutable.fromJS([1, 2, 5, 6]).zip(Immutable.fromJS([555, 666]).toJS())); // [ [1, 555], [2, 666]]

// 自定义插入规则。
// zipWith
console.log(Immutable.fromJS([1, 2, 5, 6]).zipWith((a, b) => {
return a + b;
}, Immutable.fromJS([555, 666]).toJS())); // [ 556, 668]

删除元素

1、delete(key)

// List
// delete(index: number)
// 删除 index 位置的元素
console.log(Immutable.fromJS([1, 2, 3]).delete(1).toJS(), $arr1.toJS());// [ 1, 3 ] [ 1, 2, 3]
console.log(Immutable.fromJS([1, 2, 3]).delete(77).toJS(), $arr1.toJS(), '超过范围不会强制报错');// [ 1, 2, 3] [ 1, 2, 3] 超过范围不会强制报错

// Map
console.log(Immutable.fromJS({a: {a1: 34}, b: 2, c: 3, d: 444}).delete('c').toJS(), $obj1.toJS());// {a: 1, b: 2, d: 444} {a: 1, b: 2, c: 3, d: 444}
console.log(Immutable.fromJS({a: {a1: 34}, b: 2, c: 3, d: 444}).delete('asdfasfd').toJS(), $obj1.toJS());// {a: 1, b: 2, c: 3, d: 444} {a: 1, b: 2, c: 3, d: 444}

2、deleteIn

setIn使用方式一致

3、清空元素 lear()

// List
console.log(Immutable.fromJS([1, 2, 3]).clear().toJS());// []

// Map
console.log(Immutable.fromJS({a: {a1: 34}, b: 2, c: 3, d: 444}).clear().toJS());// {}

修改元素

修改某一个元素

1、set setIn

上面已经介绍过

2、update

update(key: K, notSetValue: V, updater: (value: V) => V): Map<K, V>

// List
const $arr1 = Immutable.fromJS([1, 2, 3]);
console.log($arr1.update('2', (value)=> {
return value * 2;
}).toJS(), $arr1.toJS());// [1, 2, 6] [1, 2, 3]

console.log($arr1.update('6', 1, (value)=> {
return value * 2;
}).toJS(), $arr1.toJS());// [1, 2, 3, undefined, undefined, undefined, 2] [1, 2, 3]

console.log($arr1.update('6', 0, (value)=> { // 默认值必须大于0 感觉有BUG,所以还是不要用了。
return value * 2;
}).toJS(), $arr1.toJS());// [1, 2, 3] [1, 2, 3]

// Map
const $obj1 = Immutable.fromJS({a: {a1: 34}, b: 2, c: 3, d: 444});
console.log($obj1.update('a', (value)=> {
return value * 2;
}).toJS(), $obj1.toJS());// {a: 2, b: 2, c: 3, d: 444} {a: 1, b: 2, c: 3, d: 444}

console.log($obj1.update('e', 1, (value)=> {
return value * 2;
}).toJS(), $obj1.toJS());// {a: 1, b: 2, c: 3, d: 444, e: 2} {a: 1, b: 2, c: 3, d: 444}

console.log($obj1.update('e', 0, (value)=> { // 默认值入手是number必须大于0 感觉有BUG,所以还是不要用了。
return value * 2;
}).toJS(), $obj1.toJS());// {a: 1, b: 2, c: 6, d: 444} {a: 1, b: 2, c: 3, d: 444}

3、updateIn

使用方式和setIn一样。

获取某个元素值

1、get getIn

  • 使用方式:get(key: number, notSetValue?: T)
// List
const $test = Immutable.fromJS([1111111, 22222, {a: 888123}]);
console.log($test.get(0)); // 1111111

// 只有数组可以用 number 类型 的key
console.log(Immutable.fromJS({1: 'abc'}).get(1), Immutable.fromJS({1: 'abc'}).get('1'));// undefined "abc" | 只有数组可以用 number 类型 的key

// notSetValue 默认值,了解
console.log($test.get(11, 'no have value')); // no have value

// getIn
console.log($test.getIn(['2', 'a'], 'child no have value')); // 888123
console.log($test.getIn(['2', 'b'], 'child no have value')); // child no have value

// Map
const $test = Immutable.fromJS({a: {a1: 222}, b: 2, c: 3, d: 444});
console.log($test.get('a')); // 1111111

// notSetValue 默认值,了解
console.log($test.get('v', 'no have value')); // no have value

// getIn
console.log($test.getIn(['a', 'a1'], 'child no have value')); // 222
console.log($test.getIn(['d', 'b1'], 'child no have value')); // child no have value

2、获取头、尾元素

// List
const $arr1 = Immutable.fromJS([1, 2, 3]);
console.log($arr1.first());// 1
console.log($arr1.last());// 3

// Map
Immutable.fromJS({a: {a1: 34}, b: 2, c: 3, d: 444});
console.log($obj1.first());// {a1: 34}
console.log($obj1.last());// 444

查找某个元素

1、find() findLast()

find()findLast()返回 value

// List
console.log(Immutable.fromJS([1, 2, 56, {a: {b: 111}}]).find((value, index, array) => {
return index === 3;
}).toJS());// {a: {b: 111}}

// Map
console.log(Immutable.fromJS({a: {a1: 222}, b: 2, c: 3, d: 444}).find((value, key, obj) => {
return value === 3;
}));// 3

2、findKey() findLastKey()

findKey()findLastKey() 返回 key

// List
console.log(Immutable.fromJS([1, 2, 3, {a: {b: 111}}]).findKey((value, index, array) => {
return index === 3;
}));// 3

// Map
console.log(Immutable.fromJS({a: {a1: 222}, b: 2, c: 3, d: 444}).findKey((value, key, obj) => {
return value === 3;
}));// c

3、findEntry() findLastEntry()

findEntry()findLastEntry() 返回 key:value

// List
console.log(Immutable.fromJS([1, 2, 3, {a: {b: 111}}]).findEntry((value, index, array) => {
return index === 3;
}));// [3, Map]

// Map
console.log(Immutable.fromJS({a: {a1: 222}, b: 2, c: 3, d: 444}).findEntry((value, key, obj) => {
return Immutable.is(value, Immutable.fromJS({a1: 222}));
}));// ["a", Map]

4、keyOf() lastKeyOf()

keyOf()lastKeyOf() 根据 value 返回key

/ List
console.log(Immutable.fromJS([1, 2, 3, {a: {b: 111}}]).keyOf(Immutable.fromJS({a: {b: 111}}))); // 3
console.log(Immutable.fromJS([1, 2, 3, {a: {b: 111}}]).keyOf(2)); // 1

// Map
console.log(Immutable.fromJS({a: {a1: 222}, b: 2, c: 3, d: 444}).keyOf(Immutable.fromJS({a1: 222}))); // a
console.log(Immutable.fromJS({a: {a1: 222}, b: 2, c: 3, d: 444}).keyOf(2)); // b

List 特有查找某个元素

1、indexOf() lastIndexOf()

// 找不到 返回 -1
console.log(Immutable.fromJS([1, 2, 3, {a: {b: 111}}]).indexOf(Immutable.fromJS({a: {b: 111}}))); // 3

2、findIndex() findLastIndex()

console.log(Immutable.fromJS([1, 2, 3, {a: {b: 111}}]).findIndex((value, index, array) => {
return value/3 === 1;
})); // 2

查找最大、最小元素

max()maxBy()默认比较规则为>min()minBy()默认比较规则为>

1、max()

// List
console.log(Immutable.fromJS([1, 2, 301, 88]).max()); // 301

// 自定义比较规则
console.log(Immutable.fromJS([1, 2, 301, 88]).max((valueA, valueB) => {
return valueA > valueB;
})); // 301

// Map
console.log(Immutable.fromJS({a: 8888, b: 2, c: 3, d: 444}).max()); // 8888

// 自定义比较规则
console.log(Immutable.fromJS({a: 8888, b: 2, c: 3, d: 444}).max((valueA, valueB) => {
return valueA > valueB;
})); // 8888

2、maxBy()

// List
// 自定义比较的元素
console.log(Immutable.fromJS([{a: 2}, {a: 1}, {a: 2301}, {a: 222}]).maxBy((value, index, array) => {
return value.get('a');
}).toJS());// {a: 2301}

// 自定义比较的元素,和比较规则
console.log(Immutable.fromJS([{a: 2}, {a: 1}, {a: 2301}, {a: 222}]).maxBy((value, index, array) => {
return value.get('a');
}, (valueA, valueB) => {
return valueA > valueB;
}).toJS());// {a: 2301}

// Map
// 自定义比较的元素
console.log(Immutable.fromJS({a: {a1: 222}, b: {a1: 11}, c: {a1: 33}, d: {a1: 54654}}).maxBy((value, key, obj) => {
return value.get('a1');
}).toJS());// {a1: 54654}

// 自定义比较的元素,和比较规则
console.log(Immutable.fromJS({a: {a1: 222}, b: {a1: 11}, c: {a1: 33}, d: {a1: 54654}}).maxBy((value, key, obj) => {
return value.get('a1');
}, (valueA, valueB) => {
return valueA > valueB;
}).toJS());// {a1: 54654}

3、min()

  • max()

4、minBy()

  • maxBy()

5、keys() values() entries()

获取ES6 Iterable 迭代器

// List
const $test = List([11, 22, 33, 44]);

const keys = $test.keys();
for (let i of keys) {
console.log(i);
}

const values = $test.values();
for (let i of values) {
console.log(i);
}

const entries = $test.entries();
for (let i of entries) {
console.log(i);
}
// Map
const $test = Immutable.fromJS({a: {a1: 222}, b: 2, c: 3, d: 444});

const keys = $test.keys();
for (let i of keys) {
console.log(i); // a b c d
}

const values = $test.values();
for (let i of values) {
console.log(i); // {a1: 222} 2 3 444
}

const entries = $test.entries();
for (let i of entries) {
console.log(i);// ["a", Map] ["b", 2] ["c", 3] ["d", 444]
}

截取

1、slice()

和原生Array slice()用法一致

// List
console.log(Immutable.fromJS([1, 2, 3]).slice(0).toJS());// [1, 2, 3]

// Map
console.log(Immutable.fromJS({a: {a1: 34}, b: 2, c: 3, d: 444}).slice(0).toJS());// {a: Object, b: 2, c: 3, d: 444}
console.log(Immutable.fromJS({a: {a1: 34}, b: 2, c: 3, d: 444}).slice(1).toJS());// {b: 2, c: 3, d: 444}

2、rest() butLast()

/ List
// rest() 返回删除第一个元素后的 List
console.log(Immutable.fromJS([1, {a: 1}, 3, 4, 5, 6]).rest().rest().toJS()); // [{a: 1}, 3, 4, 5, 6]
// butLast() 返回删除最后一个元素后的 List
console.log(Immutable.fromJS([1, {a: 1}, 3, 4, 5, 6]).butLast().toJS()); // [1, {a: 1}, 3, 4, 5]

// Map
// rest() 返回删除第一个元素后的 Map
console.log(Immutable.fromJS({a: {a1: 222}, b: 2, c: 3, d: 444}).rest().rest().toJS()); // {c: 3, d: 444}
// butLast() 返回删除最后一个元素后的 Map
console.log(Immutable.fromJS({a: {a1: 222}, b: 2, c: 3, d: 444}).butLast().toJS()); // {a: {a1: 222}, b: 2, c: 3}

3、skip() skipLast() skipWhile() skipUntil()

// List

// skip(number)
// 从头按照条件抛出number个元素,对剩余元素进行截取
// 参数 数量
console.log(Immutable.fromJS([1, {a: 1}, 3, 4, 5, 6]).skip(2).toJS()); // [3, 4, 5, 6]

// skipLast(number)
// 从尾部按照条件抛出number个元素,对剩余元素进行截取
// 参数 数量
console.log(Immutable.fromJS([1, {a: 1}, 3, 4, 5, 6]).skipLast(2).toJS()); // [1, {a: 1}, 3, 4]

// skipWhile()
// 从头开始循环,抛出满足 return 条件===true 的元素。
console.log(Immutable.fromJS([111, 33 , 22, 44, 55, 66]).skipWhile((value, index, array) => {
return value > 31;
}).toJS()); // [22, 44, 55, 66]

// skipUntil()
// 从头开始循环,抛出满足 return 条件===false 的元素。
console.log(Immutable.fromJS([32, 33 , 40, 44, 55, 66]).skipWhile((value, index, array) => {
return value < 39;// 抛出直到小于39的元素。
}).toJS()); // [40, 44, 55, 66]

// Map
// skip(number)
// 从头开始循环,抛出满足 return 条件===true 的元素。
// 参数 数量
console.log(Immutable.fromJS({a: {a1: 222}, b: 2, c: 3, d: 444}).skip(2).toJS()); // {c: 3, d: 444}

// skipLast(number)
// 从尾部按照条件抛出number个元素,对剩余元素进行截取
// 参数 数量
console.log(Immutable.fromJS({a: {a1: 222}, b: 2, c: 3, d: 444}).skipLast(2).toJS()); // {a: {a1: 222}, b: 2}

// skipWhile()
// 从头开始循环,抛出满足 return 条件===true 的元素。
console.log(Immutable.fromJS({a: 1, b: 2, c: 3, d: 444}).skipWhile((value, key, obj) => {
return value === 1;
}).toJS()); // {b: 2, c: 3, d: 444}

// skipUntil()
// 从头开始循环,抛出满足 return 条件===false 的元素。
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).skipWhile((value, key, obj) => {
return value < 39;// 抛出直到小于39的元素。
}).toJS()); // {d: 444}

4、take() takeLast() takeWhile() takeUntil()

// List
// take(number)
// 从头获取几个复合条件的元素
// 参数 数量
console.log(Immutable.fromJS([1, {a: 1}, 3, 4, 5, 6]).take(2).toJS()); // [1, {a: 1}]

// takeLast(number)
// 从尾部获取几个复合条件的元素
// 参数 数量
console.log(Immutable.fromJS([1, {a: 1}, 3, 4, 5, 6]).takeLast(2).toJS()); // [5, 6]

// takeWhile()
// 从头开始循环,获取满足 return 条件===true 的元素。
console.log(Immutable.fromJS([111, 33 , 22, 44, 55, 66]).takeWhile((value, index, array) => {
return value > 31;
}).toJS()); //[111, 33]

// takeUntil()
// 从头开始循环,获取满足 return 条件===false 的元素。
console.log(Immutable.fromJS([32, 33 , 40, 44, 55, 66]).takeUntil((value, index, array) => {
return value > 41;
}).toJS()); //[32, 33 , 40]

// Map
// take(number)
// 从头获取几个复合条件的元素
// 参数 数量
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).take(2).toJS()); // {a: 5, b: 2}

// takeLast(number)
// 从尾部获取几个复合条件的元素
// 参数 数量
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).takeLast(2).toJS()); // {c: 3, d: 444}

// takeWhile()
// 从头开始循环,获取满足 return 条件===true 的元素。
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).takeWhile((value, key, obj) => {
return value > 2;
}).toJS()); //{a: 5}

// takeUntil()
// 从头开始循环,获取满足 return 条件===false 的元素。
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).takeUntil((value, key, obj) => {
return value > 39;
}).toJS()); //{a: 5, b: 2, c: 3}

循环遍历

1、map() filter() every() some() forEach() reduce() reduceRight()

// List
//1. map()
console.log(Immutable.fromJS([1, 2, 3, 4, 5]).map((value, index, array)=>{
return value * 2;
}).toJS()); // [2, 4, 6, 8, 10]

//2. filter()
console.log(Immutable.fromJS([1, 2, 3, 4, 5]).filter((value, index, array)=>{
return value % 2 === 0;
}).toJS()); // [2, 4]
// filterNot() ...这个没有什么卵用

//3. every()
console.log(Immutable.fromJS([1, 2, 3, 4, 5]).every((value, index, array)=>{
return value > 2;
})); // false

//4. some()
console.log(Immutable.fromJS([1, 2, 3, 4, 5]).some((value, index, array)=>{
return value > 2;
})); // true

//5. forEach() 返回迭代的条目数(包括返回false的最后一个迭代)
// 与Array 的 forEach不同,如果sideEffect的任何调用返回false,迭代将停止。 返回迭代的条目数(包括返回false的最后一个迭代)。
console.log(Immutable.fromJS([1, 2, 3, 4, 5, {a: 123}]).forEach((value, index, array)=>{
console.log(value, index, array.toJS(), 'forEach');
return value < 5;
})); // 5

//6. reduce()
// 同原生用法
//7. reduceRight()
// 同原生用法

// Map
//1. map()
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).map((value, key, obj)=>{
return value * 2;
}).toJS()); // {a: 10, b: 4, c: 6, d: 888}

//2. filter()
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).filter((value, key, obj)=>{
return value % 2 === 0;
}).toJS()); // {b: 2, d: 444}
// filterNot() ...这个没有什么卵用

//3. every()
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).every((value, key, obj)=>{
return value > 2;
})); // false

//4. some()
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).some((value, key, obj)=>{
return value > 2;
})); // true

//5. forEach() 返回迭代的条目数(包括返回false的最后一个迭代)
// 与Array 的 forEach不同,如果sideEffect的任何调用返回false,迭代将停止。 返回迭代的条目数(包括返回false的最后一个迭代)。
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).forEach((value, key, obj)=>{
return value < 444;
})); // 4

//6. reduce()
// 同原List用法
//7. reduceRight()
// 同List用法

Map 特有 mapKeys() mapEntries()

Map元素进行处理,返回处理后的对象

//mapKeys() 返回对象
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).mapKeys((key)=>{
return key + 'hhh';
}).toJS());
// {ahhh: 5, bhhh: 2, chhh: 3, dhhh: 444}

//mapEntries() 返回对象
console.log(Immutable.fromJS({a: 5, b: 2, c: 3, d: 444}).mapEntries(([key, value])=>{
return [key + 'aaa', value+'hhhh'];
}).toJS());// {aaaa: "5hhhh", baaa: "2hhhh", caaa: "3hhhh", daaa: "444hhhh"}

merge

merge() mergeDeep() mergeWith() mergeDeepWith()

// List
const $test = Immutable.fromJS([1, 2, 3, 7, {a: {b: 55, c: 66}}]);
const $test1 = Immutable.fromJS([1, 2, 3, 6, {a: {b: 333, d: 67}}]);

// 浅merge
console.log($test.merge($test1).toJS(), $test.toJS());
// $test1 -> $test [1, 2, 3, 6, {b: 333, d: 67}] [1, 2, 3, 7, {a: {b: 55, c: 66}}]
// 深merge
console.log($test.mergeDeep($test1).toJS(), $test.toJS());
// $test1 -> $test [1, 2, 3, 6, {b: 333, c: 66, d: 67}] [1, 2, 3, 7, {a: {b: 55, c: 66}}]

// 浅merge自定义merge规则
console.log($test.mergeWith((prev, next)=> {
// 自定义转换
return prev;
}, $test1).toJS(), $test1.toJS());
// 深merge自定义merge规则
console.log($test.mergeDeepWith((prev, next)=> {
// 自定义转换
return prev;
}, $test1).toJS(), $test1.toJS());

// Map
const $test = Immutable.fromJS({a: {a1: 222, a3: 456}, b: 2, c: 3, d: 444});
const $test1 = Immutable.fromJS({a: {a1: 222, a2: 234}, b: 2, c: 3, d: 444});

// 浅merge
console.log($test.merge($test1).toJS(), $test.toJS());
// $test1 -> $test {a: {a1: 222, a2: 234}, b: 2, c: 3, d: 444} {a: {a1: 222, a3: 456}, b: 2, c: 3, d: 444}
// 深merge
console.log($test.mergeDeep($test1).toJS(), $test.toJS());
// $test1 -> $test {a: {a1: 222, a2: 234, a3: 456}, b: 2, c: 3, d: 444} {a: {a1: 222, a3: 456}, b: 2, c: 3, d: 444}

// 浅merge自定义merge规则
console.log($test.mergeWith((prev, next)=> {
// 自定义转换
return prev;
}, $test1).toJS(), $test1.toJS());
// 深merge自定义merge规则
console.log($test.mergeDeepWith((prev, next)=> {
// 自定义转换
return prev;
}, $test1).toJS(), $test1.toJS());

jonin() 转换为字符串

使用方式和原生Arrayjoin()一样

// List
console.log(Immutable.fromJS([1, 2, 3, {a: 123, b: 321}]).join()); // 1,2,3,Map { "a": 123, "b": 321 }
// Map
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: 444}).join()); // 2,Map { "a1": 222, "a3": 456 },3,444

isEmpty() 判空

// 判断空List
console.log(Immutable.fromJS([]).isEmpty()); // true
// 判断Map是否为空 比原生方便
console.log(Immutable.fromJS({}).isEmpty()); // true

has() hasIn() 检查是否有某个key

// List
console.log(Immutable.fromJS([1, 2, 3, {a: 123, b: 321}]).has('0')); // true
console.log(Immutable.fromJS([1, 2, 3, {a: 123, b: 321}]).hasIn([3, 'b'])); // true

// Map
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: 444}).has('a')); // true
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: 444}).hasIn(['a', 'a3'])); // true

includes() 是否包含某些元素

includes()contains()这俩等效

// List
// 对象是否包含某个元素,对Immutable元素使用Immutable.is 进行比较
console.log(Immutable.fromJS([6, 5, 4, 3, 2, 1, 89]).includes('89'));// 数组没有字符89,所以返回 false
console.log(Immutable.fromJS([6, 5, 4, 3, 2, 1, '89']).contains('89'));// true
console.log(Immutable.fromJS([6, 5, 4, 3, 2, 1, Immutable.fromJS([6, 5, 4])]).contains(Immutable.fromJS([6, 5, 4])));// true

// Map
// 对象是否包含某个元素,对Immutable元素使用Immutable.is 进行比较
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: 89}).includes('89'));// 数组没有字符89,所以返回 false
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: '89'}).contains('89'));// true
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: Immutable.fromJS([6, 5, 4])}).contains(Immutable.fromJS([6, 5, 4])));// true

isSubset() 子集判断

// List
// isSubset()
console.log(Immutable.fromJS([6, 5, 1, [6, 5, 4]]).isSubset(Immutable.fromJS([[6, 5, 4], 6, 5, 4, 3, 2, 1, '89'])));// true
// isSuperset 就是 isSubset 参数掉个个儿
console.log(Immutable.fromJS([[6, 5, 4], 6, 5, 4, 3, 2, 1, '89']).isSuperset(Immutable.fromJS([6, 5, 1, [6, 5, 4]])));// true

// Map
// isSubset()
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}}).isSubset(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: 5})));// true
// isSuperset 就是 isSubset 参数掉个个儿
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: 5}).isSuperset(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}})));// true

reverse() 反转

// List
console.log(Immutable.fromJS([1, 2, 3, 4, 5, 6]).reverse().toJS());
// [6, 5, 4, 3, 2, 1]
// Map
console.log(Immutable.fromJS({b: 2, a: {a1: 222, a3: 456}, c: 3, d: 5}).reverse().toJS());
// {d: 5, c: 3, a: {a1: 222, a3: 456}, b: 2}

排序

sort()sortBy()

// List
// sort(comparator?: (valueA: V, valueB: V) => number): Iterable<K, V>
console.log(Immutable.fromJS([6, 5, 4, 3, 2, 1]).sort().toJS());
// 传入比较函数
console.log(Immutable.fromJS([1, 2, 3, 4, 5, 6]).sort((a, b) => {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
if (a === b) {
return 0;
}
}).toJS());
// sortBy
/*
sortBy<C>(
comparatorValueMapper: (value: T, key: number, iter: Iterable<number, T>) => C,
comparator?: (valueA: C, valueB: C) => number
): Iterable<number, T>
*/
console.log(Immutable.fromJS([{a: 1, b: {c: 22}}, {a: 2, b: {c: 22}}, {a: 1, b: {c: 22}},
{a: 3, b: {c: 22}}, {a: 10, b: {c: 22}}, {a: 9, b: {c: 22}}]).sortBy((value, index, array)=> {
return value.get('a')
},(a, b) => {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
if (a === b) {
return 0;
}
}).toJS());

// Map
console.log(Immutable.fromJS({b: 2, a: 88, c: 3, d: 5}).sort().toJS());// {b: 2, c: 3, d: 5, a: 88}
// 传入比较函数
console.log(Immutable.fromJS({b: 2, a: 88, c: 3, d: 5}).sort((a, b) => {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
if (a === b) {
return 0;
}
}).toJS());// {b: 2, c: 3, d: 5, a: 88}
// sortBy
/*
sortBy<C>(
comparatorValueMapper: (value: T, key: number, iter: Iterable<number, T>) => C,
comparator?: (valueA: C, valueB: C) => number
): Iterable<number, T>
*/
console.log(Immutable.fromJS({b: {a: 2}, a: {a: 88}, c: {a: 3}, d: {a: 5}}).sortBy((value, key, obj)=> {
return value.get('a')
},(a, b) => {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
if (a === b) {
return 0;
}
}).toJS());// {b: {a: 2}, c: {a: 3}, d: {a: 5}, a: {a: 88}}

flatten() 平铺

参数默认情况下,false 深度平铺,true 浅度平铺1层

// List
console.log(Immutable.fromJS([1, 2, 3, 4, [1, 11, 111, 12344], {a: 1234, b: {bb: [777, 888]}}, 5, 6]).flatten().toJS());
// [1, 2, 3, 4, 1, 11, 111, 12344, 1234, 777, 888, 5, 6]
console.log(Immutable.fromJS([1, 2, 3, 4, [1, 11, 111, 12344], {a: 1234, b: {bb: [777, 888]}}, 5, 6]).flatten(true).toJS());
// [1, 2, 3, 4, 1, 11, 111, 12344, 1234, Object, 5, 6]

// Map
console.log(Immutable.fromJS({b: 2, a: {a1: {a5: 333}, a3: [1,2,3]}, c: 3, d: 5}).flatten().toJS());
// {0: 1, 1: 2, 2: 3, b: 2, a5: 333, c: 3, d: 5}
console.log(Immutable.fromJS({b: 2, a: {a1: {a5: 333}, a3: [1,2,3]}, c: 3, d: 5}).flatten(true).toJS());
// {b: 2, a1: Object, a3: Array[3], c: 3, d: 5}

groupBy() 分组

返回值是OrderedMap

// List
console.log(Immutable.fromJS([{v: 0, a: 111}, {v: 1, a: {b: [1, 2, 3]}}, {v: 1, a: 333}, {v: 0, a: {b: [1, 2, 3]}}, {v: 1, a: 333}]).groupBy((value) => {
return value.get('a')
}).toJS());
// OrderedMap {111: Array[1], 333: Array[2], Map { "b": List [ 1, 2, 3 ] }: Array[2]}

// Map
console.log(Immutable.fromJS({b: {a5: 333}, a: {a5: 333}, c: {a5: 334}, d: {a5: 334}}).groupBy((value) => {
return value.get('a5')
}).toJS());
// OrderedMap {333: {b: {a5: 333}, a: {a5: 333}}, 334: {c: {a5: 334}, d: {a5: 334}}}

flip() Map 特有翻转

console.log(Immutable.fromJS({b: 'b1', a: 'a1', c: 'c1', d: 'd1'}).flip().toJS()); // {b1: "b", a1: "a", c1: "c", d1: "d"}

连接 concat()

// List
const $test1 = Immutable.fromJS([1, 2, 3, 4, 5, 6]);
const $test2 = Immutable.fromJS([111, 222, 333, 444, 555, 666]);
console.log($test1.concat($test2).toJS()); //[1, 2, 3, 4, 5, 6, 111, 222, 333, 444, 555, 666]
console.log($test1.toJS(), $test2.toJS()); //[1, 2, 3, 4, 5, 6] [111, 222, 333, 444, 555, 666]

// Map
const $test1 = Immutable.fromJS({b: 2, a: {a1: {a5: 333}, a3: [1,2,3]}, c: 3, d: 5});
const $test2 = Immutable.fromJS({b1: 22, b: 34});
console.log($test1.concat($test2).toJS()); //{b: 34, a: Object, c: 3, d: 5, b1: 22} 属性 b 被覆盖
console.log($test1.toJS(), $test2.toJS()); //{b: 2, a: {a1: {a5: 333}, c: 3, d: 5} b1: 22, b: 34}

类型转换

1、转换为原生类型

// List
// 浅层
// toArray
console.log(Immutable.fromJS([1, 2, 3, 4, 5, 6, {a: {b: [1234, 22]}}]).toArray());// [1, 2, 3, 4, 5, 6, Map]
console.log(Immutable.fromJS([1, 2, 3, 4, 5, 6, [1234, 22]]).toArray());// [1, 2, 3, 4, 5, 6, List]
// toObject
console.log(Immutable.fromJS([1, 2, 3, 4, 5, 6, {a: {b: [1234, 22]}}]).toObject());// {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: Map}
console.log(Immutable.fromJS([1, 2, 3, 4, 5, 6, [1234, 22]]).toObject());// {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: List}
//深层
// 就是一直在用的 toJS(); 不到万不得已,尽量不用。

// Map
// 浅层
// toArray
console.log(Immutable.fromJS({b: 2, a: {a1: {a5: 333}, a3: [1,2,3]}, c: 3, d: 5}).toArray());// [2, Map, 3, 5]
console.log(Immutable.fromJS({b: 2, a: [1, 2, 2], c: 3, d: 5}).toArray());// [2, List, 3, 5]
// toObject
console.log(Immutable.fromJS({b: 2, a: {a1: {a5: 333}, a3: [1,2,3]}, c: 3, d: 5}).toObject());// {b: 2, a: Map, c: 3, d: 5}
console.log(Immutable.fromJS({b: 2, a: [1, 2, 2]}).toObject());// {b: 2, a: List}
//深层
// 就是一直在用的 toJS(); 不到万不得已,尽量不用。

2、转换为其他ImmutableJS数据类型

// toMap()
// toOrderedMap()
// toSet()
// toOrderedSet()
// toList()
// toStack()

七、和React Redux 架构的结合

利用 immutable.js 不可变的特性,可以极大的优化React render的冗余执行。React 官方提供的PureRenderMixin是浅比较

1、immutable-pure-render-decorator

专门针对immutablePureRenderMixin,用来装饰React组件

import {React} from 'base';

import pureRenderDecorator from '../../../widgets/libs/immutable-pure-render-decorator';

@pureRenderDecorator
export default class PartA extends React.Component {
constructor(props) {
super(props);
// 舍弃React.addons.PureRenderMixin
// this.shouldComponentUpdate = React.addons.PureRenderMixin.shouldComponentUpdate.bind(this);
}

render() {
console.log('组件PartA,render执行了');
const data = this.props.data;
return (
<section>
<div>
<p>我是组件PartA</p>
<p>{data.toJSON ? JSON.stringify(data.toJSON()) : data}</p>
</div>
</section>
)
}
}

2、优化shouldComponentUpdate()

我们都知道官方提供的React.addons.PureRenderMixin提供的shouldComponentUpdate(),只能进行浅比较,对于引用类型ObjectArray比较无力,而如果使用ImmutableMapList替换ObjectArray,则可以使用Immutable.is()来比较两个引用类型,从而补充了React.addons.PureRenderMixin的漏洞。

3、高阶组件封装

对于使用immutable.js的项目,在应用公共组件的时候,由于公共组件的内部实现一定是原JS数据,所以我们只能传递原生JS数据到公共组件,但是如果转换成了原生JS数据,就又会出现"React.addons.PureRenderMixin提供的shouldComponentUpdate()`是浅比较”问题,对此可以使用下面的高阶组件进行封装

import {React} from 'base';
// 通过Immutable.is 封装过的 shouldComponentUpdate
import {shouldComponentUpdate} from '../immutable-pure-render-decorator';

export default ComposedComponent => {
return class extends React.Component {
constructor(props) {
super(props);
this.shouldComponentUpdate = shouldComponentUpdate.bind(this);
}
render() {
const props = this.props.toJS ? this.props.toJS() : this.props;
return <ComposedComponent {...this.props} {...props} />;
}
}
};

3、Demo

import {React} from 'base';
import { connect } from 'react-redux';
import highComponent from '../../../../widgets/libs/utils/highComponent';
import actions from '../../actions';

// 公共组件
import Dialog from '@alife/dialog';

// import Immutable from 'immutable';
function mapStateToProps(state) {
return {
open: state.getIn(['dialog', 'open']),
title: state.getIn(['dialog', 'title'])
}
}

function mapDispatchToProps(dispatch) {
return {
onPrimaryTouchTap: ()=> {
dispatch(actions.toggleDialog(false));
},
onSecondaryTouchTap: ()=> {
dispatch(actions.toggleDialog(false));
}
}
}

export default connect(mapStateToProps, mapDispatchToProps)(highComponent(Dialog))//通过高阶组件封装

八、思维导图总结API

九、更多参考

  • facebook.github.io/immutable-js/docs/
支持一下
扫一扫,支持poetries
  • 微信扫一扫
  • 支付宝扫一扫