Immutable 在 React 中的应用
理解 Immutable 数据结构及其在 React 项目中的使用方法
问题
什么是 Immutable?如何在 React 项目中应用?
解答
什么是 Immutable
Immutable 指一旦创建就不能被更改的数据。对 Immutable 对象的任何修改、添加或删除操作都会返回一个新的 Immutable 对象。
Immutable 基于 Persistent Data Structure(持久化数据结构)实现。当数据被修改时,会返回一个新对象,但新对象会尽可能利用之前的数据结构,避免内存浪费。
通过 Structural Sharing(结构共享),当对象树中某个节点发生变化时,只修改该节点和受影响的父节点,其他节点保持共享,避免深拷贝带来的性能损耗。
使用 immutable.js
immutable.js 提供了完整的不可变数据结构,主要数据类型包括:
- List:有序索引集,类似 Array
- Map:无序索引集,类似 Object
- Set:没有重复值的集合
常用方法:
fromJS() 和 toJS()
// JS 数据转为 Immutable
const obj = Immutable.fromJS({a: '123', b: '234'})
// Immutable 转为 JS
const jsObj = obj.toJS()
is() 比较
import { Map, is } from 'immutable'
const map1 = Map({ a: 1, b: 1, c: 1 })
const map2 = Map({ a: 1, b: 1, c: 1 })
map1 === map2 // false
is(map1, map2) // true
get() 和 getIn() 取值
let abs = Immutable.fromJS({a: {b: 2}})
abs.getIn(['a', 'b']) // 2
let arr = Immutable.fromJS([1, 2, 3, {a: 5}])
arr.getIn([3, 'a']) // 5
setIn() 赋值
import Immutable from 'immutable'
const foo = Immutable.fromJS({a: {b: 1}})
const bar = foo.setIn(['a', 'b'], 2)
console.log(foo.getIn(['a', 'b'])) // 1
console.log(foo === bar) // false
在 React 中应用
优化 shouldComponentUpdate
使用 Immutable 可以简化性能优化,通过 is() 方法快速比较,避免深度比较:
import { is } from 'immutable'
shouldComponentUpdate(nextProps, nextState) {
return !is(this.props, nextProps) || !is(this.state, nextState)
}
在组件状态中使用
import { Map } from 'immutable'
getInitialState() {
return {
data: Map({ times: 0 })
}
}
handleAdd() {
this.setState({
data: this.state.data.update('times', v => v + 1)
})
}
在 Redux 中使用
import { fromJS } from 'immutable'
import * as constants from './constants'
const defaultState = fromJS({
home: true,
focused: false,
mouseIn: false,
list: [],
page: 1,
totalPage: 1
})
export default (state = defaultState, action) => {
switch(action.type) {
case constants.SEARCH_FOCUS:
return state.set('focused', true)
case constants.CHANGE_LIST:
// 使用 merge 一次修改多个字段,效率更高
return state.merge({
list: action.data,
totalPage: action.totalPage
})
default:
return state
}
}
关键点
- Immutable 通过持久化数据结构和结构共享实现高性能的不可变数据
- 使用
is()方法可以快速比较两个 Immutable 对象,避免深度比较 - 在 React 中可以优化
shouldComponentUpdate,减少不必要的渲染 - 在 Redux 中使用 Immutable 可以简化 reducer 的编写,避免手动深拷贝
merge()方法可以一次性修改多个字段,比多次set()效率更高
目录