Immutable的优点
每次对Immutable对象的操作返回的都是一个新对象,不会出现“篡改行为”
clone行为自下而上,共同部分会被保留,自己以上的节点才会被操作,性能更好
api丰富
延迟操作等高端姿势
为什么性能快,因为用了hash maps tries和vector tries传送门:http://en.wikipedia.org/wiki/Hash_array_mapped_trie http://hypirion.com/musings/understanding-persistent-vector-pt-1
通常在redux下面需要考虑深复制和浅复制的差别,所以我们引入Immutable, 好处就不多说,直接开始。
API简单案例
romJS()
将JS对象和数组转换为不可变Map和List
let map1 = Immutable.fromJS(map);
let map2 = map1.set('a', 4);
console.log('---> map1 ' + map1.get('a'));
console.log('---> map2 ' + map2.get('a'));
//结果
---> map1 1
---> map1 4
toJS()
将Immutable数据转换为原生JS
set()
const originalList = List([ 0 ]);
// List [ 0 ]
originalList.set(1, 1);
// List [ 0, 1 ]
List().set(50000, 'value').size;
// 50001
setIn(): 进行深度赋值
const list = List([ 0, 1, 2, List([ 3, 4 ])])
list.setIn([3, 0], 999);
// List [ 0, 1, 2, List [ 999, 4 ] ]
get()
const list = List([ 0 ]);
let value = list.get(0); // 0
getIn(): 进行深度取值
const list = List([ 0, 1, 2, List([ 3, 4 ])]);
let value = list.getIn([3, 0]); // 3
is()
比较两个对象是否相等
let map1 = Immutable.fromJS(map);
let map2 = Immutable.fromJS(map);
console.log('---> map1 == map2 ' + (map1 === map2));
console.log('---> map1 == map2 ' + Immutable.is(map1, map2));
//结果
---> map1 == map2 false
---> map1 == map2 true
//因为每次返回的是不同对象,就算值完全相等,也不相等
isImmutable()
判断是否为Immutable对象
console.log('---> isImmutable([]) ' + isImmutable([]));
console.log('---> isImmutable({}) ' + isImmutable({}));
console.log('---> isImmutable(Map()) ' + isImmutable(Map()));
console.log('---> isImmutable(List()) ' + isImmutable(List()));
//结果
---> isImmutable([]) false
---> isImmutable({}) false
---> isImmutable(Map()) true
---> isImmutable(List()) true
还有很多高端操作,以及作者给我们提供的List、Map、Stack、Set、Record
等等高端货请大家自行去翻API吧传送门:http://facebook.github.io/immutable-js/docs/#/
直接使用
这是一点使用方法,导入后,在更新的生命周期进行对比,如果没有改变的item是不会刷新的,这样很好的提高了整体列表的性能。
shouldComponentUpdate(nextProps, nextState) {
let rusult1 = !Immutable.is(Immutable.Map(this.props.item[0]), Immutable.Map(nextProps.item[0]));
let rusult2 = !Immutable.is(Immutable.Map(this.props.item[0]), Immutable.Map(nextProps.item[0]));
return rusult1 || rusult2;
}
在RN+Redux的项目中使用
在第一点中我们分析了遇到的优化点,在第二点中我们讲解了能进行优化的工具,现在我们来进行具体的优化。
combineReducers的切换
我们之前combineReducers用的是Redux提供的,但是它只能处理原生JS,所以我们需要引入redux-immutable,它提供的combineReducers可以处理Immutable数据
import {createStore, applyMiddleware, compose} from 'redux';
import {combineReducers} from 'redux-immutable';
...
export default (data = Immutable.Map({})) => {
const rootReducer = combineReducers({
route: routeReducer,
modules: combineReducers(reducers)
});
return createStore(rootReducer, data, middleware);
};
每个Reducer的初始化数据也应该采用Immutable数据
const initialState = Immutable.Map({
dataList: Immutable.List([]),
count1: 0
});
与服务端数据的交互在第获取一时间转换为Immutable数据,在发送第一时间转化为原生数据
return fetch(url).then((res) => {
return res.json();
}, (er) => {console.log(er);}).then((data) => {
data = Immutable.fromJS(data || {});
dispatch({
type: GETDATA_END,
payload: {
dataList: data.get('data')
}
});
}, (error) => {
console.log(error);
dispatch({
type: GETDATA_BEGIN
});
});
这里需要注意以下两点:
如果使用安卓模拟器,且使用localhost的数据,需要直接填写localhost的ip地址。因为模拟器有自己的localhost ip,如果直接用localhost就指向了它提供的地址,而不是本机的地址了
如果使用iOS模拟器,其请求的是http协议的地址,需要在info.plist开启对http的支持,如下:
NSAppTransportSecurity
NSAllowsArbitraryLoads
因为Persistent data structire,Reducer返回的数据不用新建一个对象了
[GETDATA_END]: (state, action) => {
const {dataList} = action.payload;
return state.set('dataList', dataList);
},
shouldComponentUpdate可以进行统一处理了
shouldComponentUpdate(nextProps, nextState) {
const thisProps = this.props || {};
const thisState = this.state || {};
nextState = nextState || {};
nextProps = nextProps || {};
if (Object.keys(thisProps).length !== Object.keys(nextProps).length ||
Object.keys(thisState).length !== Object.keys(nextState).length) {
return true;
}
for (const key in nextProps) {
if (!Immutable.is(thisProps[key], nextProps[key])) {
return true;
}
}
for (const key in nextState) {
if (!Immutable.is(thisState[key], nextState[key])) {
return true;
}
}
return false;
}
函数的传递方式需要注意
如果每次render时都是重新声明的函数,则其对比会有问题,因为is()内部对函数的对比是基于ValueOf的,所以将下面的第一种方式改为第二种方式:
this.addCount()} style={Style.btnContainer}>
addCount
addCount
还有一些优缺点:
优
能便利的进行时间溯洄,便于状态的把控与调试
结构共享,节约内存
并发安全
能抽象出统一的对比函数
Model与View耦合度不高
缺
有学习成本
容易与原生函数混淆,并且原生函数一旦重写可能会导致问题
资源大小增加
跨页面数据同步方式会有变动,之前页面间进行引用传递,在B页面进行的修改会自动呈现到A页面,但是现在是Persistent data structire,因此B页面的改动A页面无感,需要特殊的触发机制来进行状态同步
因为并非原生的数据结构,所以像解构这种用法需要引入特殊的库后才能使用
参考:
React.js Conf 2015 - Immutable Data and React
Optimizing Performance
Immutable.js
Immutable.js 以及在 react+redux 项目中的实践
Immutable 详解及 React 中实践
从 React 的组件更新谈 Immutable 的应用
基于React Native及Redux的Immutable.js引入