标签:concat ble 描述 ssi 来源 blog 初始化 旅行 col
Immutable.js出自Facebook,是最流行的不可变数据结构的实现之一。它实现了完全的持久化数据结构,通过使用像tries这样的先进技术来实现结构共享。所有的更新操作都会返回新的值,但是在内部结构是共享的,来减少内存占用(和垃圾回收的失效)。
这里说的持久化是用来描述一种数据结构,指一个数据,在被修改时,仍然能够保持修改前的状态,即不可变类型。immutable.js提供了十余种不可变的类型(List,Map,Set,Seq,Collection,Range等)
Immutable使用先进的tries(字典树)技术实现结构共享来解决性能问题,当我们对一个Immutable对象进行操作的时候,ImmutableJS会只clone该节点以及它的祖先节点,其他保持不变,这样可以共享相同的部分,大大提高性能。
const oddSquares = Immutable.seq.of(1, 2, 3, 4, 5, 6, 7, 8)
.filter(item => {
console.log(‘immutable对象的filter执行‘);
return item % 2;
})
.map(x => x * x);
console.log(oddSquares.get(1)); // 9
const jsSquares = [1, 2, 3, 4, 5, 6, 7, 8]
.filter(item => {
console.log(‘原生数组的filter执行‘);
return item % 2;
})
.map(x => x * x);
console.log(jsSquares[1]); // 9
用seq创建的对象,其实代码块没有被执行,只是被声明了,代码在get(1)的时候才会实际被执行,取到index=1的数之后,后面的就不会再执行了,所以在filter时,第三次就取到了要的数,从4-8都不会再执行。如果在实际业务中,数据量非常大,一个array的长度是几百,要操作这样一个array,如果应用惰性操作的特性,会节省非常多的性能。
// Map(): 原生object转Map对象 (只会转换第一层,注意和fromJS区别)
immutable.Map({ name: ‘graceji‘, 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: ‘graceji‘, age: 18 }); // 原生object --> Map
// toJS(): immutable对象转原生js (深度转换,会将内部嵌套的Map和List全部转换成原生js)
immutableData.toJS();
// 查看List或者map大小
immutableData.size 或者 immutableData.count()
// is(): 判断两个immutable对象是否相等
const objA = { name: ‘graceji‘, age: 18 };
const objB = { name: ‘graceji‘, age: 18 };
const imA = immutable.Map({ name: ‘graceji‘, age: 18 });
const imB =immutable.Map({ name: ‘graceji‘, age: 18 });
objsA === objB // false; 比较的是地址
immutable.is(imA, imB); // true; hashcode相同
// merge() 对象合并
const imA = immutable.fromJS({ a: 1,b: 2 });
const imA = immutable.fromJS({ c: 3 });
const imC = imA.merge(imB);
console.log(imC.toJS()) // { a: 1,b: 2,c: 3 }
// 增删改查(所有操作都会返回新的值,不会修改原来值)
const immutableData = immutable.fromJS({
a: 1,
b: 2,
c: {
d: 3
}
});
const data1 = immutableData.get(‘a‘) // data1 = 1
const data2 = immutableData.getIn([‘c‘, ‘d‘]) // data2 = 3; getIn用于深层结构访问
const data3 = immutableData.set(‘a‘ , 2); // data3中的 a = 2
const data4 = immutableData.setIn([‘c‘, ‘d‘], 4); // data4中的 d = 4
const data5 = immutableData.update(‘a‘ , function(x) { return x+4 }) // data5中的 a = 5
const data6 = immutableData.updateIn([‘c‘, ‘d‘], function(x) { return x+4 }) // data6中的 d = 7
const data7 = immutableData.delete(‘a‘) // data7中的 a 不存在
const data8 = immutableData.deleteIn([‘c‘, ‘d‘]) // data8中的 d 不存在
优点:
时间旅行指的是,每时每刻的值都被保留了,想回退到哪一步只要简单的将数据取出就行。如果现在页面有个撤销的操作,撤销前的数据被保留了,只需要取出就行,这个特性在redux或者flux中特别有用
缺点:
react有个重要的性能优化的点就是shouldComponentUpdate,返回true代码该组件要re-render,false则不重新渲染。简单的场景可以直接使用===去判断this.props和nextProps是否相等,但当props是一个复杂的结构时,===肯定是没用的。
首先需要确定哪些数据需要使用不可变数据,哪些数据要使用原生js数据结构,哪些地方需要做互相转换。
Note:fromJS() 和 toJS() 是深层的互转immutable对象和原生对象,性能开销大,尽量不要使用。
import { combineReducers } from ‘redux-immutable‘;
import reducer1 from ‘./reducer1‘;
import reducer2 from ‘./reducer2‘;
import reducer3 from ‘./reducer3‘;
const rootReducer = combineReducers({
reducer1,
reducer2,
reducer3,
});
export default rootReducer;
const initialState = Immutable.Map({});
const reducer1 = (state = initialState, action) => {
switch (action.type) {
case ILOVEYOU:
return state.set(‘smile‘, true);
}
}
export default reducer1;
// connect
function mapStateToProps (state) {
return {
lovers: state.getIn([‘man‘, ‘list‘]),
abhorrers: state.getIn([‘women‘, ‘list‘]) // 使用get或者getIn来获取state中的变量
}
}
// 伪代码
$.ajax({
type: ‘GET‘,
url: ‘XXX‘,
dataType: ‘json‘,
success(res) {
res = immutable.fromJS(res || {});
callback && callback(res);
},
error(e) {
e = immutable.fromJS(e || {});
callback && callback(e);
},
});
// BaseComponent.js 基类
import React, { Component } from ‘react‘;
import { is } from ‘immutable‘;
class BaseComponent extends Component {
constructor(props, context) {
super(props, context);
}
shouldComponentUpdate (nextProps, nextState) {
const thisProps = this.props || {};
const thisState = this.state || {};
nextState = nextState || {};
nextProps = nextProps || {};
if (Object.keys(thisProps).length !== Object.keys(nextProps).length ||
Object.keys(thisState).length !== Object.keys(nextState).length) {
return true;
}
for (const key in nextProps) {
if (!is(thisProps[key], nextProps[key])) {
return true;
}
}
for (const key in nextState) {
if (!is(thisState[key], nextState[key])) {
return true;
}
}
return false;
}
}
export default BaseComponent;
组件中如果需要使用统一封装的shouldComponentUpdate,则直接继承基类, 如果不想组件使用封装的方法,那直接在该组件中重写shouldComponentUpdate就行了。
import BaseComponent from ‘./BaseComponent‘;
class People extends BaseComponent {
constructor() {
super();
}
…………
}
// js const arr = [1,2,3,4]; arr.push(5); console.log(arr); // [1,2,3,4,5] //immutable const arr = immutable.fromJS([1,2,3,4]) // 错误用法 arr.push(5); console.log(arr) //[1,2,3,4] // 正确用法 arr = arr.push(5); console.log(arr) // [1,2,3,4,5]
// es6对象复制
const state = Object.assign({}, state, {
key: value
});
// array复制
const newArr = [].concat([1, 2, 3]);
总的来说immutable.js完美的契合了react+redux的state流处理,redux的宗旨就是单一数据流,可追溯,这两点恰恰是immutable.js的优势。当然也不是所有使用react+redux的场景都需要使用immutable.js,建议满足项目足够大,state结构足够复杂的原则,小项目可以手动处理shouldComponentUpdate,不建议使用,得不偿失。
标签:concat ble 描述 ssi 来源 blog 初始化 旅行 col
原文地址:https://www.cnblogs.com/zuobaiquan01/p/13854349.html