React Native -- mobx

React Native -- mobx: 
  mobx是一个小巧优雅的库,可以帮助我们很好的管理前端状态的变更。
  其实mobx提供的不只是Component的自动更新,mobx本身提供的是一种自动更新的机制。
  ---------------------------------------------------------------------------------------------------------------------
  下面是看这个视频(作者:天地之灵)记录的笔记:http://v.youku.com/v_show/id_XMjQ4NTA4OTUwOA==.html?spm=a2hzp.8253869.0.0&from=y1.7-2#paction
  视频中项目的GitHub地址:https://github.com/tdzl2003/mobx-lesson-20170122
  
  1)概念简介 -- observable, computed, action, autorun, map
  2)入门 -- Counter
  3)入门 -- TODO List
  4)实战 -- 登录注册(表单)
  5)实战 -- 首页(分页列表)
  6)实战 -- 购物车(联动)
  7)高级 -- 计时器
  8)高级 -- autosave
  9)高级 -- Swiper优化
  
================================================================================
  安装需要的依赖:mobx 和 mobx-react。
  npm i mobx mobx-react --save


  我们也要安装一些 babel 插件,以支持 ES7 的 decorator 特性:
  npm i babel-plugin-transform-decorators-legacy babel-preset-react-native-stage-0 --save-dev


  现在,创建一个 .babelrc 文件配置 babel 插件:
{
 'presets': ['react-native'],
 'plugins': ['transform-decorators-legacy']
}
因为我们编写的是一个自定义 .babelrc 文件,所有只需要 react-native 的 preset。
配置 react-native 的 preset,还有指定一些先期运行的插件(我们这里是 transform-decorators-legacy 插件)。
======================================================================================


*********** 1)概念简介 demo1 -- observable的使用 ******************************
import { observable, autorun} from 'mobx';
export default function demo1() {
const value = observable(0);

autorun(() => {
console.log(`value is: ${value.get()}`);
});

value.set(2);
value.set(8);
value.set(-3);
}


*********** 1)概念简介 demo2 -- computed的使用 ******************************
import { observable, computed, autorun} from 'mobx';
export default function demo2() {
const value = observable(0);

const condition = computed(() => {value.get() >= 0});

autorun(() => {
console.log(`condition is: ${condition.get()}`);
});

value.set(2);
value.set(8);
value.set(-3);
}


*********** 1)概念简介 demo3 -- observable Object的使用 ******************************
import { observable, autorun} from 'mobx';
export default function demo3() {
// 返回一个对象
const value = observable({
foo: 0,
bar: 0,
get condition() {
return this.foo >= 0;
},
});

autorun(() => {
console.log(`value.foo is: ${value.foo}`);
});

autorun(() => {
console.log(`value.condition is: ${value.condition}`);
});

value.foo = 2;
value.foo = 8;
value.foo = -3;

value.bar = 1;
value.bar = 2;
}


*********** 1)概念简介 demo4 -- observable Array的使用 ************
import { observable, computed, autorun} from 'mobx';
export default function demo4() {
const value = observable([0]);

autorun(() => {
console.log(`value.length is: ${value.length}`);
});

autorun(() => {
console.log(`value[0] is: ${value[0]}`);
});

value[0] = 1;
value.push(2);
value.push(3);

value.splice(0, 1);
}


*********** 1)概念简介 demo5 -- use class and decorator,项目中多数用到这方面的知识,上面的demo只是简单介绍 *****************
import { observable, computed, autorun, action, useStrict} from 'mobx';


useStrict(true); // 使用严格规范, 强制使用@action, 推荐写法。


class Foo {
@observable
selected = 0;

@observable
items = [];

@computed
get selectedItem() {
if (this.selected >= this.items.length) {
return null;
}
return this.items[this.selected];
}

@action
addItem(item) {
this.items.push(item);
}

@action
removeAt(id) {
this.items.splice(id, 1);
if (this.selected >= id) {
this.selected--;
}
}

@action
removeSelected() {
this.items.splice(this.selected, 1);
}
}


export default function demo5() {
const foo = new Foo();

autorun(() => {
console.log(`Current selected is: ${foo.selectedItem()}`);
});

foo.addItem(0);
foo.addItem(1);
foo.addItem(2);
foo.addItem(3);

foo.selected = 2;

foo.removeSelected();

foo.removeAt(0);
}


*********** 1)概念简介 demo6 -- observable map的使用,不常用 ***************
import { autorun, map } from 'mobx'; 


export default function demo6() {
const foo = map({});

autorun(() => {
console.log(`map have ${map.size} keys`);
});

foo.set('foo', 1);
foo.set('bar', 1);
foo.set('foo', 2);
foo.delete('bar');
}








*********** 2)入门 -- Counter ******************
import React, { Component } from 'react';
import {
StyleSheet,
View,
Text,
} from 'react-native';


import { observable } from 'mobx';
import { observer } from 'mobx-react/native';


const counter = observable(0);


function inc() {
counter.set(counter.get() + 1);
}


function dec() {
counter.set(counter.get() - 1);
}


@observer
export default class Counter1 extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.value}>{counter.get()}</Text>
<Text style={styles.btn} onPress={inc}>+</Text>
<Text style={styles.btn} onPress={dec}>-</Text>
</View>
);
}
}


const styles = StyleSheet.create({
container: {

},

value: {

},

btn: {},


});


// 第二种counter,和上面的第一种不一样,第一种的值会同时变化,第二种单独变化。
@observer
export default class Counter2 extends Component {
@observable
counter = 0;

inc = () => {
++this.counter;
}

dec = () => {
--this.counter;
}

render() {
return (
<View style={styles.container}>
<Text style={styles.value}>{this.counter}</Text>
<Text style={styles.btn} onPress={this.inc}>+</Text>
<Text style={styles.btn} onPress={this.dec}>-</Text>
</View>
);
}
}


// 第三种把Text改为TextInput,用户可以输入数字
@observer
export default class Counter3 extends Component {
@observable
counter = 0;

inc = () => {
++this.counter;
}

dec = () => {
--this.counter;
}

onChangeText = v => {
try{
this.counter = parseInt(v);
} catch(err) {

}
}

render() {
return (
<View style={styles.container}>
<TextInput style={styles.value} value={`${this.counter}`} onChangeText={this.onChangeText} />
<Text style={styles.btn} onPress={this.inc}>+</Text>
<Text style={styles.btn} onPress={this.dec}>-</Text>
</View>
);
}
}








********** 3)入门 -- TODO List, 自己改成ListView了,原作者用的是ScrollView **********************
import React, {Component, PropTypes,} from 'react';
import {
    StyleSheet,
    View,
    Text,
    ScrollView,
    TouchableOpacity,
    ListView,
    Alert,
} from 'react-native';


import {observable, action} from 'mobx';
import {observer} from 'mobx-react/native';


const titles = ['Eat', 'Drink', 'Think'];


class Todo {
    id = `${Date.now()}${Math.floor(Math.random() * 10)}`;


    @observable
    title = '';


    @observable
    done = false;


    constructor(title) {
        this.title = title;
    }
}


function randomTodoTitle() {
    return titles[Math.floor(Math.random() * titles.length)];
}


@observer
class TodoItem extends Component {
    static propTypes = {
        data: PropTypes.instanceOf(Todo),
    };


    @action
    onPress = () => {
        const {data} = this.props;
        data.done = !data.done;
    };


    render() {
        const {data} = this.props;
        return (
            <Text
                style={[styles.item, data.done && styles.done]}
                onPress={this.onPress}
            >
                {data.title}
            </Text>
        );
    }
}


@observer
export default class MobxDemoTodoList extends Component {


    static title = '3 - TodoList';


    renderItem(data) {
        return (<TodoItem key={data.id} data={data}/>);
    }


    render() {
        return (
            <ListView dataSource={this.state.dataSource}
                      renderRow={(data, non, sid) => { return this.renderItem(data)}}/>
        );
    }


    constructor(props) {
        super(props);
        const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        this.state = {
            dataSource: ds.cloneWithRows([
                new Todo('Eat'),
                new Todo('D'),
                new Todo('T'),
                new Todo('Eat'),
                new Todo('D'),
                new Todo('T'),
                new Todo('Eat'),
                new Todo('D'),
                new Todo('T'),
                new Todo('Eat'),
                new Todo('D'),
            ])
        };
    }
}


const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: 'white',
    },


    content: {
        justifyContent: 'center',
        alignItems: 'center',
    },


    todo: {
        fontSize: 20,
    },


    item: {
        fontSize: 30,
        margin: 20,
        color: '#f00',
    },


    done: {
        fontSize: 30,
        margin: 20,
        color: '#ccc',
        textDecorationLine: 'line-through', // 一条横线从文本中间穿过
    },
});






********** 4)实战 -- 登录注册(表单) **********************
import validate from 'mobx-form-validate';
import { observable, toJS } from 'mobx';


// 自己定义的component
import { FormProvider, FormItem, Submit } from './components/form';


/*
// 第1种,不用@validate
class LoginForm {
@observable
mobile = '';

@observable
pwd = '';

@computed
get mobileValidateError() {
return /^1\d{10}$/.test(this.mobile) ? null : 'Please input a valid phone number.';
}

@computed
get pwdValidateError() {
return /^.+$/.test(this.pwd) ? null : 'Please input any password.';
}

@computed
get validateError() {
return this.mobileValidateError || this.pwdValidateError;
}

@computed
get isValid() {
return !this.validateError;
}
} */


// 第2种
class LoginForm {
@observable
@validate(/^1\d{10}$/, 'Please input a valid phone number.')
mobile = '';

@observable
@validate(/^.+$/, 'Please input any password.')
pwd = '';

submit = async () => {
// await post('/login', toJS(this));
alert(JSON.stringify(toJS(this)));
}
}


export default class LoginPage extends Component {
static title = '4 - Login Form';
form = new LoginForm();
render() {
return (
<FormProvider form={this.form}>
<View style={styles.container}>
<FormItem name="mobile" underlineColorAndroid="transparent">Mobile<FormItem>
<FormItem secureTextEntry name="pwd">Password<FormItem>
<Submit onSubmit={this.form.submit}>Login</Submit>
</View>
</FormProvider>
);
}
}


@observer
export default class FormItem extends Component {
  static propTypes = {
    name: PropTypes.string.isRequired,
    form: PropTypes.object,
    children: PropTypes.string.isRequired,
    autoFocus: PropTypes.boolean,


    ...TextInput.propTypes,
  };
  static contextTypes = {
    form: PropTypes.object,
  };
  state = {
    focused: this.props.autoFocus,
  };
  onChangeText = (text) => {
    const { name } = this.props;
    const form = this.context.form || this.props.form;
    form[name] = text;
  };
  onFocus = () => {
    if (!this.state.focused) {
      this.setState({ focused: true });
    }
  };
  render() {
    const { name, children, form: _, ...others } = this.props;
    const { focused } = this.state;
    const form = this.context.form || this.props.form;


    return (
      <View style={styles.container}>
        <View style={styles.row}>
          <Text style={styles.label}>{children}</Text>
          <View style={styles.inputWrapper}>
            <TextInput
              {...others}
              onFocus={this.onFocus}
              value={form[name]}
              onChangeText={this.onChangeText}
              style={styles.input}
            />
          </View>
        </View>
        <View>
          {focused && <Text style={styles.error}>{form[camelCase('validateError', name)]}</Text>}
        </View>
      </View>
    );
  }
}


export default class FormProvider extends Component {
  static propTypes = {
    // eslint-disable-next-line react/forbid-prop-types
    form: PropTypes.object,
    children: PropTypes.element.isRequired,
  };


  static childContextTypes = {
    form: PropTypes.object,
  };


  getChildContext() {
    return {
      form: this.props.form,
    };
  }
  render() {
    return React.Children.only(this.props.children);
  }
}


@observer
export default class Submit extends Component {
  static propTypes = {
    children: PropTypes.string.isRequired,
    form: PropTypes.object,
    onSubmit: PropTypes.func,
  };
  static contextTypes = {
    form: PropTypes.object,
  };
  render() {
    const { children, onSubmit } = this.props;
    const form = this.context.form || this.props.form;
    return (
      <TouchableOpacity
        style={[styles.button, form.isValid && styles.active]}
        disabled={!form.isValid}
        onPress={onSubmit}
      >
        <Text>{children}</Text>
      </TouchableOpacity>
    );
  }
}




********** 5)实战 -- 首页(分页列表) **********************

没记笔记


********** 6)实战 -- 购物车(联动) **********************

没记笔记


********** 7)高级 -- 计时器 **********************

没记笔记


********** 8)高级 -- autosave **********************

没记笔记


********** 9)高级 -- Swiper优化 **********************

没记笔记



  



mobx与redux比较


1.视图更新
mobx:按需更新
redux:自上而下


2.列表支持
mobx:良好
redux:很差


3.代码量
mobx:少
redux:多


4.安全性
mobx:一般
redux:良好


5.严谨性
mobx:自由
redux:严谨


6.性能
mobx:高
redux:中等,特定场景低下


7.插件
mobx:不多、一般不用
redux:丰富、选择困难


8.异步操作
mobx:方便
redux:方便


9.主动通知
mobx:不方便
redux:部分场景不方便


10.服务端渲染
mobx:不支持
redux:支持,但有毒


11.自动化测试
mobx:一般
redux:极为方便


12.数据可回溯
mobx:不可
redux:可


13.用途
mobx:广泛,偏重数据&局部状态
redux:有毒,偏重全局性


14.适用范畴
mobx:快速迭代的项目,中小团队、分工不细、表单较多的项目

redux:大型、持续较久的项目,分工细致的团队,编辑器等涉及数据回溯的功能









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值