React-Native Mobx

作者: 我是C | 来源:发表于2017-05-31 12:12 被阅读365次

    记录一下在学习React-Native所需要的技能.
    在用mobx之前一定要对mobx 有一些初步了解,慢慢去敲代码,才能发现这个东西的妙处!

    什么是mobx?
    mobx:一种状态监听.在我理解,例如,它是监听对象里的某一个属性.如果被监听的对象属性发生了改变,会触发对应的render(重新渲染).这种监听机制类似于iOS的KVC.

    为什么用mobx不用state?
    mobx 会render对应的子页面,而且状态管理一目了然,对于状态多的界面mobx性能更优,状态管理更方便.而state 会渲染整个父页面,如果状态多了.

    运用 mobx :

    1.首先导入mobx 库

    "dependencies": {
        "mobx": "^3.1.9",
        "mobx-react": "^4.1.8",
      },
      "devDependencies": {
        "babel-plugin-transform-decorators-legacy": "^1.3.4"
      }
    

    babel-plugin-transform-decorators-legacyES7的装饰器模式插件,也就是@observable 这种,同时需要在package.json同级目录下创建一个.babelrc文件,文件里的内容如下

      "presets": ["react-native"],
      "plugins": [
        "syntax-decorators",
        "transform-decorators-legacy"
      ]
    }
    

    在package.json里对应写入,然后npm install

    mobx 几种关键字:
    网上搜索了很多,发现不好理解,下面是我自己的理解
    observable:监听的对应属性
    computed:根据监听属性,计算出来的新值
    action:对监听属性的对应操作
    runInAction:在action里,在一个loop event里返回处理属性(意思等等被监听属性修改完,一起返回);
    computedrunInAction 可以没有,剩下两个在没有 你也没法监听了

    举例:运用在列表请求里,对应标注↓

    <1>请求一个列表
    //导入
    import {observable, computed, action, runInAction} from 'mobx';
    
    export default class HJNetListUtil{
        @observable listData = [];//监听的数组
        @observable errorMsg = ''//监听的错误信息
        @observable page = 1 //监听的上下拉页数
        @observable loading = false //监听是否正在请求
        @observable isMore = true //是否是最后一页
        @observable refreshing = false; //是否正在刷新
      
            //构造函数,比如new HJNetListUtil(),对应传的参数
        constructor(url,params,listKey) {
            url = gBaseUrl.baseUrl + url;//拼接URL baseUrl是域名, url是链接
            this.listKey = listKey;//对应的解析字段(比如list:[],data:[]看你们服务器返回的是什么)
            this.url = url;
            this.params = params;
            this.params['page'] = this.page;
            this.POST();
        }
    
        @action //对应的POST 请求 用了action
        POST(params){
            if (!this.loading) {
                this.loading = true;
                if (params) {
                    this.params = params;
                    this.params['page'] = this.page;
                }
                if (this.page ==1 ) {this.refreshing = true}
                NetUtil.POST(
                this.url,
                this.params,
                (data)=>this.successCallback(data),
                (error)=>this.failCallback(error)
                );
            }
        }
        
    
        successCallback(data){
    
            this.errorMsg = '';
            this.refreshing = false;
            var list = [];
            if (this.listKey) {
                list = data.data[listKey];
            }else{
                list = data.data.list;
            }
            
        //这个地方可以用@computed 计算list.length的长度
    
            if (!list.length) {
                this.isMore = false;
                this.loading = false;
                return;
            }
            if (this.page == 1) {
                this.listData.replace(list);//第一页刷新
            }else{
                this.listData.push(...list);//拼接数组
            }
            this.loading = false;
        }
    
        failCallback(error){
            this.loading = false;
            this.errorMsg = error;
        }
    }
    

    对应的控件↓,我将没用的删除掉

    'use strict';
    import {observer} from 'mobx-react/native';
    
    @observer
    export default class HomeCategoryList extends React.Component {
    
      static defaultProps = {
          listStore:Object,
        };
    
      render() {
        const {listData,loading,refreshing} = this.props.listStore;
        return (
          <View style={styles.containStyle}>
            <FlatList
                numColumns={2}
                data={listData.slice()}
                renderItem={this._renderItem}
                ItemSeparatorComponent={this._renderSeparator}
                ListFooterComponent={this._renderFooter}
                onEndReached={()=>this._onEndReach()}
                onEndReachedThreshold={0.1}
                onRefresh={()=>this._onRefresh()}
                refreshing={refreshing}
                keyExtractor={(item, index) => index}
              />
          <Loading isShow={this.props.listStore.isMore && loading} />
          </View>
        );
      }
    

    1.import {observer} from 'mobx-react/native';导入
    2.@observer监听的类
    3.const {listData,loading,refreshing} = this.props.listStore;从对象中取出对应被监听的属性,这时只要属性一变,就会重新渲染该控件,this.props.listStore是父控件传过来的,如果是本类应该写

    var params = {
            keyWord:'',
        }
    this.listStore = new HJNetListUtil('url',params);
    

    不过new HJNetListUtil一定要在render 之前创建,一般写在constructor ()函数里.
    4.listData.slice() 数组拷贝,如果不写拷贝,那么数组即使变化也不会触发控件render.(应该是地址没变就不会触发render)


    <2>.滑动条,选项卡,最好用第二种方法
    8F76D445-7985-4784-A086-92382F215D5B.png

    对应的界面应该这样写

    'use strict';
    
    import {observable, computed, action, runInAction,autorun} from 'mobx';
    
    import React,{Component} from 'react';
    import {observer} from 'mobx-react/native';
    
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View,
      Alert,
      Image,
      TouchableOpacity,
      ListView
    } from 'react-native';
    
    
    //待办事项行数据
    class TodoListItem {
    
        index;
    
        @observable
        title;
    
        @observable
        seleted = false;
    
        @action
        toggleFinish() {
            if (!this.seleted) {this.seleted = true}
        }    
    }
    
    //待办事项列表数据
    class TodoListHolder {
        @observable
        dataList = [];
        @computed
        get taskLeft() {
            return this.dataList.filter((it) => it.seleted == true);
        }
        @action
        clear(){}
    }
    
    
    
    @observer
    export default class HomeSlider extends React.Component {
    
      todoList = new TodoListHolder();
    
    
    
      static defaultProps = {
          list :[
              'John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie', 'Devin'
          ]
      };
    
      ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    
      pre = 0;
    
      // 初始化模拟数据
      constructor(props) {
        super(props);
        for (let i = 0; i < this.props.list.length; i++) {
                let listItem = new TodoListItem();
                if (i == 0) {listItem.seleted = true}
                listItem.title = this.props.list[i];
                listItem.index = i;
                this.todoList.dataList.push(listItem)
            }
    
        autorun(() => {
        var arr = this.todoList.dataList.filter((it) => it.seleted == true);
        var c = 0;
        if (arr.length>1) 
        {
            // console.log('保持的',this.pre);
    
          for (var i = 0; i < arr.length; i++) {
            var item = arr[i];
    
            if (item.index === this.pre) {
              // console.log('上一个',this.pre);
              this.todoList.dataList[this.pre].seleted = false;
            }else{
              c = item.index;
              // console.log('现在的',this.pre);
            }
    
          }
          this.pre = c;
           // console.log('-----------')
    
        }
      })
    
      };
       
    
      render() {
        return (
          <View style={styles.containStyle}>
            <ListView
              dataSource={this.ds.cloneWithRows(this.todoList.dataList.slice())}
              renderRow={this.renderRow.bind(this)}
              horizontal={true}
              showsHorizontalScrollIndicator={false}
            />
          </View>
        );
      }
    
      renderRow(rowData,sectionID,rowID){
        return(
          <Item rowData={rowData}/>
        )
      }
    
      
    }
    
    
    
    
    @observer
    export class Item extends React.Component {
      render(){
        return(
          <TouchableOpacity activeOpacity={0.5} onPress={()=>this.props.rowData.toggleFinish()}>
            {this.renderItem()}
          </TouchableOpacity>
        )
      }
    
      renderItem(){
    
        if (this.props.rowData.seleted) {
          return(
            <View style={styles.topClickStyle_S}>
            <Text style={styles.topTextStyle}>{this.props.rowData.title}</Text>
            </View>
          )
        }else {
          return(
            <View style={styles.topClickStyle}>
            <Text>{this.props.rowData.title}</Text>
            </View>
    
          )
        }
      }
    }
    
    const styles = StyleSheet.create({
      containStyle:{
        flex:1,
        marginLeft:10,
        marginRight:10,
      },
    
      SeparatorComponent:{
        height:10,
        backgroundColor:'#dddddd'
      },
      topClickStyle:{
        height:30,
        width:60,
        marginRight:5,
        backgroundColor:'white',
        justifyContent:'center',
        alignItems:'center',
    
      },
      topClickStyle_S:{
        height:30,
        width:60,
        marginRight:5,
        backgroundColor:'white',
        justifyContent:'center',
        alignItems:'center',
        borderBottomWidth:2,
        borderBottomColor:'red',
      },
      topTextStyle:{
    
        color:'red',
      }
    })
    

    监听属性改变会触发autorun.在这里可以做很多事情

    第二种方法,比较简单

    'use strict';
    
    import {observable, computed, action, runInAction,autorun} from 'mobx';
    
    import React,{Component} from 'react';
    import {observer} from 'mobx-react/native';
    
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View,
      Alert,
      Image,
      TouchableOpacity,
      ListView
    } from 'react-native';
    
    
    //待办事项行数据
    class TodoListItem {
    
        redModel = null;
    
        constructor(redModel) {
          this.redModel = redModel;
        }
    
        @action
        select=()=>{
    
          if (this.redModel.selectedItem == this) {
            this.redModel.selectedItem = null;
          }else {
            this.redModel.selectedItem = this
          }
        }
    
        @computed
        get seleted(){
          return this.redModel.selectedItem === this;
        }
    
        title;   
    }
    
    //待办事项列表数据
    class TodoListHolder {
    
        @observable
        selectedItem=null;
    
    
        @observable
        dataList = [];
    }
    
    
    
    @observer
    export default class Slider extends React.Component {
    
      todoList = new TodoListHolder();
    
      constructor(props) {
          super(props);
          for (let i = 1; i < 30; i++) {
              let listItem = new TodoListItem(this.todoList);
              listItem.title = `待办事项${i}`;
              this.todoList.dataList.push(listItem)
          }
          this.todoList.selectedItem = this.todoList.dataList[0];
      }
    
      ds = new ListView.DataSource({
            rowHasChanged: (r1, r2) => {
                return r1 !== r2
            }
      });
       
    
      render() {
        return (
          <View style={styles.containStyle}>
            <ListView
              dataSource={this.ds.cloneWithRows(this.todoList.dataList.slice())}
              renderRow={this.renderRow.bind(this)}
              horizontal={true}
              showsHorizontalScrollIndicator={false}
            />
          </View>
        );
      }
    
      renderRow(rowData,sectionID,rowID){
        return(
          <Item rowData={rowData}/>
        )
      }
    
      componentDidMount() {
    
      }
      
    }
    
    
    
    
    @observer
    export class Item extends React.Component {
      render(){
        return(
          <TouchableOpacity activeOpacity={0.5} onPress={()=>this.props.rowData.select()}>
            {this.renderItem()}
          </TouchableOpacity>
        )
      }
    
      renderItem(){
    
        if (this.props.rowData.seleted) {
          return(
            <View style={styles.topClickStyle_S}>
            <Text style={styles.topTextStyle}>{this.props.rowData.title}</Text>
            </View>
          )
        }else {
          return(
            <View style={styles.topClickStyle}>
            <Text>{this.props.rowData.title}</Text>
            </View>
    
          )
        }
      }
    }
    
    const styles = StyleSheet.create({
      containStyle:{
        flex:1,
        marginLeft:10,
        marginRight:10,
      },
    
      SeparatorComponent:{
        height:10,
        backgroundColor:'#dddddd'
      },
      topClickStyle:{
        height:30,
        marginRight:15,
        backgroundColor:'white',
        justifyContent:'center',
        alignItems:'center',
    
      },
      topClickStyle_S:{
        height:30,
        marginRight:15,
        backgroundColor:'white',
        justifyContent:'center',
        alignItems:'center',
        borderBottomWidth:2,
        borderBottomColor:'red',
      },
      topTextStyle:{
    
        color:'red',
      }
    })
    
    

    总结

    仔细看会发现其实主要就这几步

    1.定义一个对象,在对象里监听你想监听的属性(@observable 属性)
    2.@observer对应的控件,在render() 里将你监听的属性取出来
    3.然后赋值到控件上,赋值数组的时候要注意拷贝

    相关文章

      网友评论

        本文标题:React-Native Mobx

        本文链接:https://www.haomeiwen.com/subject/jmbdfxtx.html