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

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

你可能感兴趣的:(关于React-Native使用immutable(redux环境下)的一点用法)