從問題說起:熟悉 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 dom
,virtual dom
通過diff
修改dom
,來實現高效的dom
更新。 - 但是有一個問題。當
state
更新時,如果數據沒變,你也會去做virtual dom
的diff
,這就產生了浪費。這種情況其實很常見
- 當然你可能會說,你可以使用
PureRenderMixin
來解決呀,PureRenderMixin
是個好東西,我們可以用它來解決一部分的上述問題 - 但
PureRenderMixin
只是簡單的淺比較,不使用於多層比較。那怎么辦?自己去做復雜比較的話,性能又會非常差
- 方案就是使用
immutable.js
可以解決這個問題。因為每一次state
更新只要有數據改變,那么PureRenderMixin
可以立刻判斷出數據改變,可以大大提升性能
Immutable 優點
- Immutable 降低了 Mutable 帶來的復雜度
可變( Mutable
)數據耦合了 Time
和 Value
的概念,造成了數據很難被回溯
- 節省內存
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
表示開始值,默認值為0
,end
表示結束值,默認為無窮大,step
代表每次增大的數值,默認為1
.如果start = end
,則返回空集合。Repeat()
: 返回一個vSeq.Indexe
類型的集合,這個方法有兩個參數,value
代表需要重復的值,times
代表要重復的次數,默認為無窮大。Record
: 一個用於生成Record
實例的類。類似於JavaScript
的Object
,但是只接收特定字符串為key
,具有默認值。Seq
: 序列,但是可能不能由具體的數據結構支持。Collection
: 是構建所有數據結構的基類,不可以直接構建
上面那么多常用的也就是 List
和 Map
五、幾個重要的API
1、fromJS()
fromJS()
是最最最常用的將原生JS
數據轉換為ImmutableJS
數據的轉換方法。使用方式類似於JSON.parse()
,接收兩個參數:json
數據和reviver
函數- 在不傳遞
reviver
函數的情況下,默認將原生JS
的Array
轉為List
,Object
轉為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、toJS()
先來看官網的一段話: immutable
數據應該被當作值而不是對象,值是表示該事件在特定時刻的狀態。這個原則對理解不可變數據的適當使用是最重要的。為了將 Immutable.js
數據視為值,就必須使用 Immutable.is()
函數或 .equals()
方法來確定值相等,而不是確定對象引用標識的 ===
操作符
- 所以
toJS()
就是用來對兩個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
OrderedMap
是 Map
的變體,它除了具有 Map
的特性外,還具有順序性,當開發者遍歷 OrderedMap
的實例時,遍歷順序為該實例中元素的聲明、添加順序。 OrderedMap
比非有序 Map
更昂貴,並且可能消耗更多的內存。如果真要求遍歷有序,請使用 List
4、List
List
數據類型,對應原生 Array
數組。和原生數組,最大區別不存在’空位’。 [, , , , ]
console.log(List([,,,,]).toJS());// [undefined, undefined, undefined, undefined]
六、API
我們主要介紹 Map
和 List
創建
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
數據類型也擁有 pop
、 push
、 shift
、 unshift
這四種操作方法,和原生 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
// 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() 轉換為字符串
使用方式和原生 Array
的 join()
一樣
// 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
專門針對 immutable
的 PureRenderMixin
,用來裝飾 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()
,只能進行淺比較,對於引用類型 Object
、 Array
比較無力,而如果使用 Immutable
的 Map
和 List
替換 Object
、 Array
,則可以使用 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))//通過高階組件封裝