在项目中常常会遇到一些问题,好比把一个对象赋值给另一个对象后,如何实现修改被赋值的对象而原对象不变;通常作法是copy,而copy又分为shallowCopy(浅拷贝)和 deepCopy(深拷贝);shallowCopy对于层级比较深的对象来讲然并*用,那么只能用deepCopy来避免上面遇到的状况,但deepCopy是一个很耗性能的操做。再好比使用react技术栈来作项目时,常常须要咱们手工去判断某些组件是否须要从新渲染来减小咱们可爱又傲娇的DOM操做,react提供shouldComponentUpdate钩子函数来判断该组件树是否须要从新渲染,在该钩子函数中通常使用浅比较和深比较来判断该组件树是否须要从新渲染;若是只是浅比较,只须要PureRender就能知足,那么须要深比较呢? 上面瞎逼逼一堆废话无非是想说用immutable的好处,它能解决这些问题呀,它的共享结构多牛比呀,零学习成本让你开开心心玩时间旅行。react
immutable据说是Facebook 工程师 Lee Byron 花费 3 年时间打造,与 React 同期出现,但没有被默认放到 React 工具集里(React 提供了简化的 Helper);immutable一旦被建立终身不会变化,每次增长或修改仍是删除都是返回一个新的对象;immutable内部采用Structure Sharing(结构共享)来避免每一次deepCopy的性能损耗,每一次增删改都只会改变当前节点和父节点并返回一个新对象。git
据说 Immutable 能够给 React 应用带来数十倍的提高,我的感受10应该达不到,可是确实提高很多效率和避免因对象被修改而致使的错误,虽然能够在项目中使用Object.assign或者lodash来避免原对象被修改而致使的一些错误,可是这两货也有不少缺点,Object.assign只能深拷贝一个层级,并且你会发现满屏的Object.assign,对于处女座的做者确定是不能容忍此事的发生;Immutable提供了is方法,由于Immutable内部使用的是Trie 数据结构,因此只须要比较hashCode或valueOf来避免深度比较。github
下面介绍一下immutable中经常使用的map和list的一些基础用法,固然还有不少其余类型( Collection、Set、Record、Seq等),本文介绍一些经常使用API让读者了解使用immutable基本是零学习成本,固然你也能够选择功能更单一的seamless-immutable,代码库很是小,压缩后下载只有 2K:redux
将js转换成immutable对象:数组
immutable.Listbash
immutable.Map数据结构
在react中使用immutable时应该注意避免出现toJS操做,由于toJS和fromJS是把整个数据结构遍历一遍,还要建立新对象来保存值,是很耗性能的操做;建议项目中所有使用immutable,数据从服务请求回来转化成immutable再给redux,只有在提交数据和使用第三方不支持immutable组件或者插件时才转化成原生对象;下面是使用immutable的开发流程。less
//操做对象以前拷贝
let newState = Object.assign({}, this.state.obj, {
'a': 'test'
});
//操做以前数组的拷贝
let newArr = [...arr, ...arr1];
复制代码
//使用immutable来初始化状态
this.state = Map(obj);
//改变state的值
this.setState(this.state.set('a', 'test'));
复制代码
当react中使用了redux来进行状态管理时如何在项目中使用immutable,因为 Redux 中内置的 combineReducers和 reducer 中的 initialState 都为原生的 Object 对象,因此不能和 Immutable 原生搭配使用;可是能够经过重写combineReducers或者直接使用redux-immutablejs,本文介绍如何使用redux-immutablejs。函数
按照 Redux 的工做流,咱们从建立 store 开始。Redux 的 createStore 能够传递多个参数,前两个是: reducers 和 initialState工具
const initialState = immutable.Map({
list: [],
card: {
id: '',
title: '',
desc: ''
}
});
复制代码
在reducer里把之前的Obejct.assagin操做所有去掉,转换成immutable对象。
export default function list(state = initialState, action) {
let card;
switch (action.type) {
case types.EDIT_ENTRY:
let lists = state.get('list');
lists = lists.push(action.newData.get('data'));
card = action.newData.get('card');
return state.set('list', lists).set('card', card);
case types.VALUE_CHANGE:
return state.set('card', action.card);
case types.ADD:
return state.set('card', action.card);
default:
return state;
}
}
复制代码
在action里面的全部对象都是immutable,为了区分原生对象,请不要在有的地方使用js原生对象,有的地方使用immutable对象,这样每每会拔苗助长,容易混淆和immutable和原生转换时性能的消耗。
export function editData() {
let card = Map({
id: '',
title: '',
desc: ''
});
return { type: types.ADD, card };
}
复制代码
若是你不传递 initialState,redux-immutable也会帮助你在 store 初始化的时候,经过每一个子 reducer 的初始值来构建一个全局 Map 做为全局 state。固然,这要求你的每一个子 reducer 的默认初始值是 immutable的。只须要引入redux-immutable就能够在redux里面使用immutable了,
import {
combineReducers
} from 'redux-immutable';
import list from './list/listRedux';
const rootReducer = combineReducers({
list
});
export default rootReducer;
复制代码
function mapStateToProps(state) {
return {
listMain: state.get('list')
};
}
export default connect(mapStateToProps)(Main);
复制代码
immutable不是全部的项目都适合使用,在业务简单数据关联性不复杂等条件下使用反而增长了项目的复杂度,经过上面的开发流程你们也应该看出了immutable侵入性仍是杠杠的,因此若是是项目起初考虑上immutable是能够的;可是对于老项目中使用就的考虑一下得失了。