Immutable
每次修改Immutable对象都会创建一个新的不可变对象,在新对象上操作都不会影响到原对象的数据
深拷贝与浅拷贝
浅拷贝
只复制引用,不复制一个新的对象
arr = { }; arr2 = arr
Object.assign() 只是一级属性复制,只比浅拷贝多了一层
深拷贝
复制一个新的对象
const obj1 = JSON.parse(JSON.stringify(obj)) 数组、对象都好用 (缺点:不能有undefined)
Immutable优化性能
Immutable实现的原理是Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据
要保证旧数据同时可用且不变。同时要避免deepCopy把所有节点都复制一遍带来的性能消耗
Immutable使用了Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,
其他节点进行共享
Map
Map方法将对象数据类型封装成Immutable对象
get(‘key’) 获取对象中的键为key的值
set(‘key’,‘value’) 设置对象中键为key的条目的值为value
Immutable对象.toJS() 将Immutable对象转换成普通的js对象
Immutable对象每次操作都会返回一个新的深拷贝的对象
同时支持链式操作
// eg:
import { Map, List } from 'immutable'
const obj = {
name:'cc',
age:20
}
const oldImmuObj = Map(obj)
const newImmuObj = oldImmuObj.set('name','raccon').set('age',21)
console.log(newImmuObj,newImmuObj.get('name'))
当对象中嵌套对象是 通过Map只能转换一层Immutable对象 里面嵌套的对象不为Immutable对象结构
所以需要多层封装
const obj = Map({
name:'cc',
age:20,
filter:Map({
text:'',
up:true,
down:false
})
})
多层封装的好处 :因为react中对象数据只要更新就会更新所有需要用到这个对象的组件
当我们只需要更新其中一部分时 比如 父组件的属性obj中的name更新 但是传入子组件的filter对象没有更新
此时应该让子组件不更新来节省性能 但是只要对象发生了改变均会重新渲染
但如果对象是Immutable对象 改变name时其他属性均不会改变(地址也不变)
因此可以在子组件的shouldComponentUpdate中进行比较来判断子组件是否需要更新
// eg:
import React, { Component } from 'react'
class Child extends Component {
shouldComponentUpdate(nextProps, nextState){
if(this.props.filter === nextProps.filter){
return false
}
return true
}
render() {
return (
<div>Child</div>
)
}
}
setIn
当对象结构层次较多时需要多层的get才能获取到
可以通过Immutable.setIn()来设置深层的对象属性
const obj = Map({
name:'cc',
age:20,
filter:Map({
text:'',
up:true,
down:false
})
})
const oldImmuObj = Map(obj)
const newImmuObj = oldImmuObj.setIn(['name'],'raccon').setIn(['filter','text'],'文本')
// 第一个参数为数组 数组中为需要进入的结构,第二个参数为修改的内容
console.log(newImmuObj,newImmuObj.get('name'))
List
List方法将数组数据类型封装为Immutable数组
Immutable数组拥有原生数组的所有方法 且调用方法返回的都是以一个深拷贝的数组
不会影响旧的数组数据结构
const arr = List([1,2,3])
const arr2 = arr.push(4)
console.log(arr,arr2)
updateIn
Immutable数组也有update方法修改浅层数据
当数组结构层次较多时
可以通过Immutable.updateIn()来设置深层的数组属性
const arr = List([1,2,3,List([4,5,6])])
const brr = arr.updateIn([3],(list) => list.push(3))
// 第一个参数为数组 数组中为需要进入的结构,可以为键也可以为索引,第二个参数为回调函数 返回值为修改后的数组
console.log(brr);
fromJS - toJS
实际情况下不知道接收到的数组是什么结构
可以用 普通对象.fromJS() 将数据转化为Immutable对象
当多层结构嵌套时也会将内层数据结构转换为Immutable数据结构
操作完成后用 Immutable对象.toJS() 转换为原生js对象