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,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,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,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'),
])
};
}
}
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,
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,
onSubmit: PropTypes.func,
};
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>
);
}
}
没记笔记
********** 6)实战 -- 购物车(联动) **********************
没记笔记
********** 7)高级 -- 计时器 **********************
没记笔记
********** 8)高级 -- autosave **********************
没记笔记
********** 9)高级 -- Swiper优化 **********************
没记笔记
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:大型、持续较久的项目,分工细致的团队,编辑器等涉及数据回溯的功能
原文链接:https://www.f2er.com/react/304032.html