您的位置:首页 > Web前端 > React

关于React-Native使用immutable(redux环境下)的一点用法

2017-09-25 22:14 1136 查看
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的支持,如下:

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

因为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的,所以将下面的第一种方式改为第二种方式:

<TouchableOpacity onPress={() => this.addCount()} style={Style.btnContainer}>
<Text style={Style.btnWord}>addCount</Text>
</TouchableOpacity>

<TouchableOpacity onPress={this.addCount} style={Style.btnContainer}>
<Text style={Style.btnWord}>addCount</Text>
</TouchableOpacity>

还有一些优缺点:



能便利的进行时间溯洄,便于状态的把控与调试

结构共享,节约内存

并发安全

能抽象出统一的对比函数

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引入

作者:江湖人称_赫大侠

链接:http://www.jianshu.com/p/638880152889

來源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: