简介

每次修改一个 Immutable 对象时都会创建一个新的不可变的对象,在新对象上操作并不会影响到原对象的数据。

作用

  1. 深拷贝:react修改数据时,不想让原数据发生改变,所有使用拷贝再赋值的方式。但 const obj1 = JSON.parse(JSON.stringify(obj)); 的缺点: 不能有undefined,否则会遗失(没有完全实现深拷贝)
  2. 优化新能: Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要 保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用 了 Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点, 其它节点则进行共享。

image.png

基本用法

Map & List -创建(单个)

  • get:获取
  • set:设置

    1. const { Map } = require('immutable');
    2. const map1 = Map({ a: 1, b: 2, c: 3 });
    3. const map2 = map1.set('b', 50);
    4. map1.get('b') + " vs. " + map2.get('b'); // 2 vs. 50
  • List可以使用数组方法

    1. //assert.equal()函数是nodejs提供的断言函数,测试实际参数和预期参数之间的相等性。如果条件为真,则不会产生输出,否则会引发断言错误。
    2. const { List } = require('immutable');
    3. const list1 = List([ 1, 2 ]);
    4. const list2 = list1.push(3, 4, 5);
    5. const list3 = list2.unshift(0);
    6. const list4 = list1.concat(list2, list3);
    7. assert.equal(list1.size, 2);
    8. assert.equal(list2.size, 5);
    9. assert.equal(list3.size, 6);
    10. assert.equal(list4.size, 13);
    11. assert.equal(list4.get(0), 1);
    12. //push, set, unshift or splice 都可以直接用,返回一个新的immutable对象

    merge & concat -合并

  • merge:合并对象

  • concat:合并数组

    1. const { Map, List } = require('immutable');
    2. const map1 = Map({ a: 1, b: 2, c: 3, d: 4 });
    3. const map2 = Map({ c: 10, a: 20, t: 30 });
    4. const obj = { d: 100, o: 200, g: 300 };
    5. const map3 = map1.merge(map2, obj);
    6. // Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 }
    7. const list1 = List([ 1, 2, 3 ]);
    8. const list2 = List([ 4, 5, 6 ]);
    9. const array = [ 7, 8, 9 ];
    10. const list3 = list1.concat(list2, array);
    11. // List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

    toJS -解析

  • toObject:将Map转换回来

  • toArray:将List转换回来
  • toJS:将两者都转换

    1. const { Map, List } = require('immutable');
    2. const deep = Map({ a: 1, b: 2, c: List([ 3, 4, 5 ]) });
    3. console.log(deep.toObject()); // { a: 1, b: 2, c: List [ 3, 4, 5 ] }
    4. console.log(deep.toArray()); // [ 1, 2, List [ 3, 4, 5 ] ]
    5. console.log(deep.toJS()); // { a: 1, b: 2, c: [ 3, 4, 5 ] }
    6. JSON.stringify(deep); // '{"a":1,"b":2,"c":[3,4,5]}'

    fromJS -创建(多个)

  • fromJS:深层次添加Map和List

  • getIn:获取(深)
  • setIn:设置(深)
  • updateIn:回调函数更新(深)
  • mergeDeep:保留自身情况下并深克隆且转换为Map和List ```javascript const { fromJS } = require(‘immutable’); const nested = fromJS({ a: { b: { c: [ 3, 4, 5 ] } } }); // Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } }

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 //如果取一级属性 直接通过get方法,如果取多级属性 getIn([“a”,”b”,”c”]])

//setIn 设置新的值 const nested3 = nested2.setIn([ ‘a’, ‘b’, ‘d’ ], “kerwin”); // Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: “kerwin” } } }

//updateIn 回调函数更新 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)); // Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }

<a name="g3k9h"></a>
# Redux中使用
```javascript
//reducer.js
const initialState = fromJS({ //转换为Map和List
  category:"",
  material:""
})
const reducer = (prevstate = initialState,action={})=>{
  let {type,payload} = action
  switch(type){
    case GET_HOME:
      //set方法设置(不改变initialState)
      var newstate =prevstate.set("category",fromJS(payload.category))
      var newstate2 =newstate.set("material",fromJS(payload.material))
      return newstate2;
    default:
      return prevstate
   }
}

//home.js
const mapStateToProps = (state)=>{
  return {
    //getIn深层次获取state数据
    category:state.homeReducer.getIn(["category"]) || Map({}),
    material:state.homeReducer.getIn(["material"]) || Map({})
  }
}
this.props.category.get("相关属性")
this.props.category.toJS() //或者转成普通对象