1. 介绍
假设当前 redux 的大小为 1G,现在要修改 redux 树中的某个节点(节点的大小很小),我们就需要深复制整棵 redux 树,只为了修改很少的数据,这样对于性能的损耗是非常大的。于是我们使用 Immutable 来对这一现象进行优化,Immutable 只会深复制发生改变的节点及其祖先节点,然后修改后返回新数据。
Immutable.js 出自 Facebook,是非常流行的不可变数据结构的实现之一。它实现了完全的持久化数据结构,使用结构共享。所有的更新操作都会返回新的值,但是在内部结构是共享的,来减少内存占用。
- 持久化数据结构:这里说的持久化是用来描述一种数据结构,指一个数据,在被修改时,仍然能够保持修改前的状态,即不可变类型。
- 结构共享:Immutable 使用先进的 tries (字典树)技术实现结构共享来解决性能问题,当我们对一个 Immutable 对象进行操作的时候, ImmutableJS 会只 clone 该节点以及它的祖先节点,其他保持不变,这样可以共享相同的部分,大大提高性能。
- 惰性操作:创建的对象时其实代码块没有被执行,只是被声明了,代码在获取或修改的时候才会实际被执行
Immutable 的安装:yarn add immutable
2. 优缺点
-
优点
-
缺点
- 需要重新学习api
- 容易与原生对象混淆:由于api与原生不同,混用的话容易出错
- 第3方组件库不支持,使用时,还需要转换
3. 对象处理
使用 Map 和 formJS 方法将 js 对象转化为 immutable 对象,并获取数据:
import React, { Component } from 'react'
import { Map, List, fromJS } from 'immutable'
console.log("============ Map方法 ==============")
const state = { id: 1, name: '张三' }
const imState = Map(state)
console.log(imState)
console.log(imState.get('name'))
console.log(imState.getIn(['name']))
console.log("========== formJs方法 ============")
const state1 = { id: 1, name: { username: '李四' } }
const imState1 = fromJS(state1)
console.log(imState)
console.log(imState1.get('name').get('username'))
console.log(imState1.getIn(['name', 'username']))
class App extends Component {
render() {
return (
<div>
<h3>App组件之immutablejs学习</h3>
</div>
)
}
}
export default App
修改数据:
import React, { Component } from 'react'
import { Map, List, fromJS } from 'immutable'
const state = { id: 1, name: { username: '李四', age: 10 } }
const imState = fromJS(state)
const newImState = imState.set('id', 3)
console.log('newImState:',newImState.toJS(), imState.toJS())
const newImState1 = imState.setIn(['name', 'age'], 20)
console.log('newImState1:',newImState1.toJS())
const newImState2 = imState.update('id', val => val + 1)
console.log('newImState2:',newImState2.toJS())
const newImState3 = imState.updateIn(['name', 'age'], val => val + 1)
console.log('newImState3:',newImState3.toJS())
class App extends Component {
render() {
return (
<div>
<h3>App组件之immutablejs学习</h3>
</div>
)
}
}
export default App
删除数据:
import React, { Component } from 'react'
import { Map, List, fromJS } from 'immutable'
const state = { id: 1, name: { username: '李四', age: 10 } }
const imState = fromJS(state)
const newImState = imState.remove('id')
console.log(newImState.toJS())
class App extends Component {
render() {
return (
<div>
<h3>App组件之immutablejs学习</h3>
</div>
)
}
}
export default App
合并数据:
import React, { Component } from 'react'
import { Map, List, fromJS } from 'immutable'
const id = fromJS({ id: 1 })
const name = fromJS({ name: '张三' })
const imState1 = name.merge(id)
const imState2 = name.concat(id)
console.log(imState1.toJS())
console.log(imState2.toJS())
class App extends Component {
render() {
return (
<div>
<h3>App组件之immutablejs学习</h3>
</div>
)
}
}
export default App
4. 数组处理
查看长度和获取数据:
import React, { Component } from 'react'
import { Map, List, fromJS } from 'immutable'
const state = [1, 2, { name: '张三' }]
const imState = fromJS(state)
console.log(imState.size);
console.log(imState.get(2).get('name'))
console.log(imState.getIn([2, 'name']))
class App extends Component {
render() {
return (
<div>
<h3>App组件之immutablejs学习</h3>
</div>
)
}
}
export default App
修改数据:
import React, { Component } from 'react'
import { Map, List, fromJS } from 'immutable'
const state = [1, 2, { name: '张三', arr: [20] }]
const imState = fromJS(state)
const newImState1 = imState.set(0, 10)
console.log(newImState1.toJS())
const newImState2 = imState.setIn([2,'arr',0], 10)
console.log(newImState2.toJS())
const newImState3 = imState.update(0, val => val + 1)
console.log(newImState3.toJS())
const newImState = imState.updateIn([2, 'arr', 0], v => v + 1)
console.log(newImState.toJS())
class App extends Component {
render() {
return (
<div>
<h3>App组件之immutablejs学习</h3>
</div>
)
}
}
export default App
删除元素:
import React, { Component } from 'react'
import { Map, List, fromJS } from 'immutable'
const imState = fromJS([1, 2, { name: '张三', arr: [20] }])
const newImState = imState.remove(1)
console.log(newImState.toJS())
class App extends Component {
render() {
return (
<div>
<h3>App组件之immutablejs学习</h3>
</div>
)
}
}
export default App
5. 优化组件渲染
immutable 中有一个 is 方法,可以比较两个immutable对象值是否一致,如果一致则返回true 否则为false。
import React, { Component } from 'react'
import _ from 'lodash'
import { Map, List, fromJS, is } from 'immutable'
const obj1 = fromJS({ id: 1 })
const obj2 = fromJS({ id: 1 })
console.log(obj1 == obj2)
console.log(is(obj1, obj2))
class App extends Component {
render() {
return (
<div>
<h3>App组件之immutablejs学习</h3>
</div>
)
}
}
export default App
利用这个方法,我们可以优化组件渲染,例如下面这种情况:
App.jsx:
import React, { Component } from 'react'
import Child from './components/Child'
class App extends Component {
state = {
user: { num: 100 }
}
render() {
return (
<div>
<h3>App组件之immutablejs学习 -- {this.state.user.num}</h3>
<hr />
<Child user={this.state.user} />
<hr />
{}
{}
{}
<button onClick={() => this.setState({ user: { num: Date.now() } })}>+++++</button>
</div>
)
}
}
export default App
子组件:
import React, { Component } from 'react'
import { fromJS, is } from 'immutable'
class Child extends Component {
shouldComponentUpdate(nextProps, nextState) {
return !is(fromJS(nextProps), fromJS(this.props))
}
render() {
console.log('child -- render')
return (
<div>
<h3>child组件</h3>
</div>
)
}
}
export default Child
6. immutable和redux集合使用
安装:
redux 中利用 combineReducers 来合并 reducer 并初始化 state ,redux 自带的 combineReducers 只支持 state 是原生 js 形式的,所以需要使用 redux-immutable 提供的 combineReducers 来替换原来的方法。
yarn add redux-immutable
使用:
它的合并是支持immutable对象合并:
import { combineReducers } from 'redux-immutable'
把所有的reducer数据转换为immutable对象:
import {fromJS} from 'immutable'
const defaultState = fromJS({})
|