Immutable.js github地址:https://github.com/immutable-js/immutable-js
介绍
每次修改一个immutable对象时都会创建一个新的不可变的对象,在新对象上操作并不会影响到原
对象的数据,那Immutable这个库的实现是深拷贝还是浅拷贝?
深拷贝与浅拷贝的关系
(1)var arr = {}; arr2 = arr 浅拷贝
(2)Object.assign()只是一级属性复制,比浅拷贝多拷贝了一层而已
(3)const obj1 = JSON.parse(JSON.stringfy(obj));数组,对象都好用的方法,是深拷贝(缺点:
属性中不能有undefined,如果属性中有undedined,在进行拷贝的时候会忽略该属性)
Immutable优化性能的方式
Immutable实现的原理是Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新
数据时,要保证旧数据同时可用且不变,同时为了避免deepCopy把所有节点都复制一遍带来的性
能损耗,Immutable使用了Strctural Sharing(结构共享),即如果对象树中的一个节点发生变化,
只修改这个节点和受它影响的腹肌诶单,其他节点则进行共享。
Immutable中常用类型有Map, List
Immutable使用
下载:npm i immutable
引入:import {Map, List} from 'immutable'
Map使用
使用说明:
1.对定义的对象进行包裹,返回一个相同的新对象
2.如何修改属性-------通过.set('要修改的属性', ‘要修改的结果’)
3.如何得到属性--------通过.get('要得到的属性值的属性名')
4.如何将immutable对象转化为普通对象--------toJS()
示例:
import { Map } from 'immutable'
const obj = {
name:'xiaojian',
age:18
}
// 对原对象进行immutable包装返回一个新的对象
const oldImmutable = Map(obj)
// 修改原对象中的属性并将修改后的原对象赋值给新的对象
const newImmutable = oldImmutable.set('name', 'xiaoliu')
console.log(oldImmutable, newImmutable);
// 1.get获取immutable
console.log(oldImmutable.get('name'), newImmutable.get('name'));
// 2.将immutable转化为普通的对象使用
console.log(oldImmutable.toJS(), newImmutable.toJS());
输出结果:
组件使用一:
// // 定义state时使用Map包装后的对象
export default class App extends Component {
state = {
info:Map({
name:'xiaojian',
age:18
})
}
render() {
return (
<div>
<button onClick={() => {
this.setState({
info:this.state.info.set('name', 'xiaoliu').set('age', 28)
})
}}>修改按钮</button>
{this.state.info.get('name')} -- {this.state.info.get('age')}
</div>
)
}
}
组件使用二:
// 定义state的时候使用普通对象
export default class App extends Component {
state = {
info:{
name:'xiaojian',
age:18
}
}
render() {
return (
<div>
<button onClick={() => {
const old = Map(this.state.info)
const newImmu = old.set('name', 'xiaoliu').set('age', 28)
this.setState({
info:newImmu.toJS()
})
}}>修改按钮</button>
{this.state.info.name} -- {this.state.info.age}
</div>
)
}
}
父子组件传值:
如何手动解决在父子组件之间传递参数时在修改父组件数据,而子组件数据不变的情况下,不重新
渲染子组件而带来的性能优化,可以通过shouldComponentUpdate函数来实现
import React, { Component } from 'react'
import { Map } from 'immutable';
export default class App extends Component {
state = {
info:Map({
name:'xiaojian',
select:'aa',
filter:Map({
text:'',
up:true,
down:false
})
})
}
componentDidMount() {
// console.log(this.state.info);
}
render() {
return (
<div>
<button onClick={() => {
this.setState({
info:this.state.info.set('name', 'xiaoming')
})
}}>更新</button>
{this.state.info.get('name')}
<Child filter={this.state.info.get('filter')}/>
</div>
)
}
}
class Child extends Component{
shouldComponentUpdate(nextProps, nextState) {
if (this.props.filter === nextProps.filter) {
return false
}
return true
// console.log(nextProps, nextState);
}
render() {
return <div>
child
</div>
}
componentDidUpdate() {
console.log('componentDidUpdate');
}
}
List使用:
说明:List主要是为数组服务,为了降低immutable中List的学习成本,其中封装的方法与array的方
法的作用是一样的
js示例代码:
import { List } from 'immutable'
const arr = List([1, 2, 3])
// 添加元素可以使用push,不会影响老的对象结构
const arr2 = arr.push(4)
console.log(arr, arr2);
输出结果:
组件示例:
import React, { Component } from 'react'
import { List } from 'immutable'
export default class App extends Component {
state = {
favo:List(['aa', 'bb', 'cc'])
}
render() {
return (
<div>
{
this.state.favo.map(item => {
return <li key={item}>{item}</li>
})
}
</div>
)
}
}
}
同时使用Map, List
import { Map, List } from 'immutable'
import React, { Component } from 'react'
export default class App extends Component {
state = {
info:Map({
name:'小剑',
location:Map({
province:'四川',
city:'成都'
}),
favor:List(['读书','看报', '写代码'])
})
}
render() {
return (
<div>
<h1>个人信息修改页面</h1>
<button onClick={() => {
this.setState({
info:this.state.info.set('name', '小明').set('location', this.state.info.get('location').set('city', '北京'))
})
}}>修改</button>
<div>
{this.state.info.get('name')}
<br/>
{this.state.info.get('location').get('province')}----{this.state.info.get('location').get('city')}
<br/>
{this.state.info.get('favor').map((item, index) => {
return <li key={item}>{item}<button style={{marginLeft:'10px'}} onClick={() => {
console.log(index);
this.setState({
info:this.state.info.set('favor', this.state.info.get('favor').splice(index, 1))
})
}}>del</button></li>
})}
</div>
</div>
)
}
}
问题:同时使用Map和List会造成代码的书写很麻烦,为了解决这个问题,从Immutable中引入
fromJS进行代码的优化
fromJs实现对象的深克隆
用法说明:
1.如何读取属性-----------通过.get('属性名')获得
2.如何修改对象中的属性--------------通过setIn([ ], '修改后的值')
说明:数组中可以是一个参数,也可以是多个参数,如果只是一个参数,说明修改的值是最外层的
属性,如果有多层对象则依次写入即可
3.如何修改数组中的属性---------通过updateIn([ ], () => { } )
示例代码:
import { fromJS } from 'immutable'
import React, { Component } from 'react'
export default class App extends Component {
state = {
info:fromJS({
name:'小剑',
location:{
province:'四川',
city:'成都',
a:{
b:1111,
h:2222
}
},
favor:['读书','看报', '写代码']
})
}
componentDidMount() {
console.log(this.state.info);
}
render() {
return (
<div>
<h1>个人信息修改页面</h1>
{/* setIn(参数一, 参数二)
第一个参数是一个数组,数组可以的是一个元素,也可以是两个元素
第二个参数是修改后的内容
*/}
<button onClick={() => {
this.setState({
info:this.state.info.setIn(['name'], '小明').setIn(['location', 'city'], '上海').setIn(['location','a', 'b'], '0000000000000')
})
}}>修改</button>
<div>
{this.state.info.get('name')}
<br/>
{this.state.info.get('location').get('province')}----{this.state.info.get('location').get('city')}--{this.state.info.get('location').get('a').get('b')}
<br/>
{this.state.info.get('favor').map((item, index) => {
return <li key={item}>{item}<button style={{marginLeft:'10px'}} onClick={() => {
// this.setState({
// info:this.state.info.set('favor', this.state.info.get('favor').splice(index, 1))
// })
this.setState({
info:this.state.info.updateIn(['favor'], (list) => {
return list.splice(index, 1)
})
})
}}>del</button></li>
})}
</div>
</div>
)
}
}