不可变数据 (Immutable Data
)就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是持久化数据结构
( Persistent Data Structure),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的s性能损耗,Immutable 使用了 结构共享
(Structural Sharing),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享
,也就是Immutable会做按需改变,只会把需要更改的节点做改变,其它的节点没有变。
优点:
缺点:
参考官网重点讲解数据不可变数据的创建、更新及比较方式。
终端中执行yarn add immutable -S
,安装immutable到生产环境中。
list.get(下标)
list.size
List.isList(list)
push()
、unshift()
、concat()
、map()
import { List } from 'immutable'
const list = List([1, 2, 3, 4])
const newList = list.push(5)
console.log(list, newList) //List{..} List{..}
console.log(list[4], newList[4]) // undefined undefined
console.log(list.get(4), newList.get(4)) // undefined 5
console.log(list.size, newList.size) // 4 5
const arr = [1, 2, 3, 4]
console.log(List.isList(list), List.isList(arr)) // true false
push()
在list尾部添加数据,返回新的immutable对象unshift()
在list首部添加数据,并返回新的immutable对象concat()
连接多个list,并返回新的immutable对象map()
对list 进行遍历,类似js数组中map的使用,返回一个新的immutable对象join()
将list数组拼接成字符串toJs()
将immutable对象转成js对象import { List } from 'immutable'
const list = List([1, 2, 3, 4])
const list1 = list.push(5)
const list2 = list1.unshift(0)
const list3 = list.concat(list1, list2)
const list4 = list.map(v => v * 2)
console.log("list,",list.toJS()) //[1,2,3,4]
console.log("list1,",list1.toJS()) //[1,2,3,4,5]
console.log("list2,",list2.toJS()) //[0,1,2,3,4,5]
console.log("list3,",list3.toJS()) //[1,2,3,4,1,2,3,4,5,0,1,2,3,4,5]
console.log("list4,",list4.toJS()) //[2,4,6,8]
map.set(key,value)
,会返回一个新的变量map.get(key)
Map.isMap(obj)
,来判断是否是一个immutable.Map类型merge()
toObject()
或者 toJS()
import { Map } from 'immutable'
const map = Map({a: 1,b: 2,c: 3})
// immutable数据每次都是生成新的再重新调用set进行修改,所以需要重新赋值给一个新的变量
const newMap = map.set('b', 20)
console.log(map, newMap) // Map{...} Map{...}
console.log(map.b, newMap.b) // undefined undefined
console.log(map.get('b'), newMap.get('b')) // 2 20
const obj = {a: 1,b: 2,c: 3}
console.log(Map.isMap(map), Map.isMap(obj)) // true false,
map()
对map数据进行遍历,第一个参数对应map中的value,第二个参数对应map中的keytoJs()
将immutable对象转成js对象toObject()
将immutable对象转成js对象fromJs()
将js对象转换成immutable对象merge()
将immutable对象或者js对象进行合并,当集合发生冲突时,后面的数据会覆盖前面的数据,它只能用在immutable对象上import { Map } from 'immutable'
const alpha = Map({a: 1,b: 2,c: 3})
const objKeys = alpha.map((value, key) => key)
console.log(objKeys.join()) // a, b, c
const map1 = Map({a: 1, b: 2})
const map2 = Map({c: 3,d: 4})
const obj1 = {d: 400,e: 50}
const obj2 = {g: 500,h: 60}
const mergedMap = map1.merge(map2, obj1)
const mergeObj1=map2.merge(obj1) //obj1里的d会覆盖map2里面的d
// const mergeObj2=obj1.merge(obj2) //报错 merge()是immutable对象的方法
console.log(mergedMap.toObject()) //{a: 1, b: 2, c: 3, d: 400, e: 50}
console.log(mergedMap.toJS()) //{a: 1, b: 2, c: 3, d: 400, e: 50}
console.log(mergeObj1.toJS()) //{c: 3, d: 400, e: 50}
immutable对象
是否相等
map.equals(anotherMap)
如果值相等的话,返回trueis(map,anotherMap)
如果值相等的话,返回trueimport { Map, is } from 'immutable'
const map = Map({a: 1,b: 2,c: 3})
const anotherMap = Map({a: 1,b: 2,c: 3})
console.log(map == anotherMap) // false
console.log(map === anotherMap) // false
console.log(map.equals(anotherMap)) // 使用equals进行比较 true
console.log(is(map, anotherMap)) // 使用is进行比较 true
mergeDeep()
,像merge()一样用来合并数据,可以对嵌套数据进行深度递归getIn()
用来获取嵌套数据的值,nested.getIn([‘a’,‘b’,‘c’]) 表示获取a.b.c的值updateIn()
用来更新嵌套数据的值,第一个参数表示要更新的数据,第二个参数表示更新后的值const { fromJS } = require('immutable');
const obj={
a:{
b:{
c:[3,4,5]
}
}
}
const nested = fromJS(obj);
const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } });
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }
console.log(nested2.getIn([ 'a', 'b', 'd' ])); // 6
const nested3 = nested2.updateIn([ 'a', 'b', 'd' ], value => value + 1);
console.log(nested3);
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }
const nested4 = nested3.updateIn([ 'a', 'b', 'c' ], list => list.push(6));
console.log(nested4)
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }
redux官网推荐使用redux-immutable进行redux和immutable的集成。几个注意点:
终端中执行yarn add redux-immutable -S
,安装redux-immutable到生产环境中。
redux
中,利用combineReducers
来合并多个reduce
, redux
自带的combineReducers
只支持原生js形式的,所以需要使用redux-immutable
提供的combineReducers
来代替。
下面用一个计数器的案例来分析:
// 使用redux-immutable提供的combineReducers方法替换redux里的combineReducers
import {combineReducers} from 'redux-immutable'
import counter from './reducerCounter'
import anotherReducer from './anotherReducer'
const rootReducer = combineReducers({
counter,
anotherReducer
});
export default rootReducer;
reducer
中的initialState
也需要初始化成immutable
类型,使用set
或setIn
来更改值, get
或者getIn
来取值,比如一个counter的reducer:
import { Map } from 'immutable'
import ActionTypes from '../actions'
const initialState = Map({count: 0})
export default (state = initialState, action) => {
switch (action.type) {
case ActionTypes.INCREAMENT:
return state.set('count', state.get('count') + 1)
case ActionTypes.DECREAMENT:
return state.set('count', state.get('count') - 1)
default:
return state
}
}
state
成为了immutable
类型,connect
的mapStateToProp
也需要相应的改变,永远不要在mapStateToProps里使用toJS
方法,因为它永远返回一个新的对象。
const mapStateToProps = state => ({
count: state.getIn(['counter', 'count'])
})
在shouldComponentUpdate
里就可以使用immutable.is
或者instance.equals
来进行数据的对比了。