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

MobX 在 React Native开发中的应用

2017-07-14 13:57 239 查看
MobX 是一款精准的状态管理工具库,如果你在 React 和 React Native 应用中使用过 Flux、Alt、Redux 和 Reflux,那毫不犹豫地说,MobX 的简单性将成为你状态管理的不二之选。

加入我们要实现这样一个功能:创建一个新的列表,向列表中加入新的条目并刷新,这就用到了MobX的状态管理。



环境配置

首先,我们为MobX配置相关的环境支持。

1.npm i mobx mobx-react --save //引入mobx
2.npm i babel-plugin-transform-decorators-legacy babel-preset-react-native-stage-0 --save-dev //能够使用@标签
3.在项目目录下找到.babelrc文件,并修改为{
"presets": ["react-native"],
"plugins": ["transform-decorators-legacy"]
}


现在我们项目配置好了,可以写代码了。不过在开发之前需要对

mobx标签

mobx常用的标签做一个解释。

@observable: 使用此标签监控要检测的数据;

@observer: 使用此标签监控当数据变化是要更新的Component(组件类)

@action:使用此标签监控数据改变的自定义方法(当在需要数据改变的时候执行此自定义方法,那么View层也会跟着自动变化,默认此View层已经使用@observer标签监控)

mobx实例1

下面实现一个使用mobx实现一个简单的数据复制更新功能。

import React, {Component} from 'react';
import {
View,
StyleSheet,
ScrollView,
Text,
} from 'react-native';

/*
* 引入头文件
* */
import {observable, action} from 'mobx';
import {observer} from 'mobx-react/native';

/*
* 添加数据
* */
const datas = [
{name:'苹果',count:0},
{name:'梨',count:0},
{name:'香蕉',count:0},
{name:'草莓',count:0},
{name:'橘子',count:0},
];

/*
* 对整个列表添加观察,观察列表个数的变化
* */
@observer
export default class MobxTestSecond extends Component {

/*
* 数据管理器
* */
dataManager = new DataSource();

componentWillMount() {
/*
* 赋值初始数据
* */
this.dataManager.replace(datas);
}

/*
* 添加一个新的Item
* */
addItem = () => {
let item = {name:'西瓜',count:0};
this.dataManager.addItem(item)
};

/*
* 删除第一个Item
* */
deleteItem = () => {
this.dataManager.deleteItem(0);
};

render() {
return (
<View style={styles.container}>
<View style={styles.addItemView}>
<Text style={styles.addItem} onPress={this.addItem}>增加</Text>
<Text style={styles.addItem} onPress={this.deleteItem}>删除</Text>
</View>
<ScrollView>
{
this.dataManager.dataSource.slice(0).map((item,i)=> <ItemView key = {i} item = {item}/>)
}
</ScrollView>
</View>
);
}
}

/*
* 对每一个Item添加观察,改变个数
* */
@observer
class ItemView extends Component {

countAdd = () => {
this.props.item.add();
};

countDec = () => {
this.props.item.dec();
};

render() {
const {item} = this.props;
return (
<View style={styles.itemContainer}>
<Text>{item.name}</Text>
<Text>{item.count}</Text>
<Text style={styles.btn} onPress={this.countAdd}> + </Text>
<Text style={styles.btn} onPress={this.countDec}> - </Text>
</View>
);
}
}

/*
* 整个列表页数据管理器
* */
class DataSource {
// 本地数据源
@observable
dataSource = [];

// 添加初始数据
@action
replace = (items) => {
// 1. 清空原数据
this.dataSource.splice(0, this.dataSource.length);

// 2. 加载新数据
items.map((item, i) => {
this.dataSource.push(new Item(item));
});
};

// 添加新数据
@action
addItem = (item) => {
this.dataSource.unshift(new Item(item));
};

// 删除一条数据
@action
deleteItem = (idx) => {
this.dataSource.splice(idx, 1);
};
}
/*
* 单条Item数据管理器
* */
class Item {

/*
* 商品名称(此值是不变的所以不需要检测此值)
* */
name;

/*
* 监控商品个数
* */
@observable
count;

constructor(item) {
this.name = item.name;
this.count = item.count;
};

/*
* 商品个数+1
* */
@action
add = () => {
this.count += 1;
};

/*
* 商品个数-1
* */
@action
dec= () => {
this.count > 0 && (this.count -= 1);
};
}


案例2

新建一个 listStore.js文件。

从 mobx 导入 observable – observable

可以给存在的数据结构如对象、数组和类增加可观察的能力。简单地给类属性增加一个 @observable 装饰器(下一代

ECMAScript),或者调用 observable 或 extendObservable 函数(ES5);

创建一个叫做 ObservableListStore 的类;

创建一个可观察的数组 list;

创建三个操作列表数组的方法;

创建一个 ObservableListStore 的实例 observableListStore;

导出 observableListStore

import {observable} from 'mobx'

let index = 0

class ObservableListStore {
@observable list = []

addListItem (item) {
this.list.push({
name: item,
items: [],
index
})
index++
}

removeListItem (item) {
this.list = this.list.filter((l) => {
return l.index !== item.index
})
}

addItem(item, name) {
this.list.forEach((l) => {
if (l.index === item.index) {
l.items.push(name)
}
})
}
}

const observableListStore = new ObservableListStore()
export default observableListStore


现在已经用了存储器,我们修改项目的入口文件,使用存储,创建导航。

import React, { Component } from 'react'
import App from './app/App'
import ListStore from './app/mobx/listStore'

import {
AppRegistry,
Navigator
} from 'react-native'

class ReactNativeMobX extends Component {
renderScene (route, navigator) {
return <route.component {...route.passProps} navigator={navigator} />
}
configureScene (route, routeStack) {
if (route.type === 'Modal') {
return Navigator.SceneConfigs.FloatFromBottom
}
return Navigator.SceneConfigs.PushFromRight
}
render () {
return (
<Navigator
configureScene={this.configureScene.bind(this)}
renderScene={this.renderScene.bind(this)}
initialRoute={{
component: App,
passProps: {
store: ListStore
}
}} />
)
}
}

AppRegistry.registerComponent('ReactNativeMobX', () => ReactNativeMobX)


现在,我们来创建应用组件。实现对数据的操作。

import React, { Component } from 'react'
import { View, Text, TextInput, TouchableHighlight, StyleSheet } from 'react-native'
import {observer} from 'mobx-react/native'
import NewItem from './NewItem'

@observer
class TodoList extends Component {
constructor () {
super()
this.state = {
text: '',
showInput: false
}
}
toggleInput () {
this.setState({ showInput: !this.state.showInput })
}
addListItem () {
this.props.store.addListItem(this.state.text)
this.setState({
text: '',
showInput: !this.state.showInput
})
}
removeListItem (item) {
this.props.store.removeListItem(item)
}
updateText (text) {
this.setState({text})
}
addItemToList (item) {
this.props.navigator.push({
component: NewItem,
type: 'Modal',
passProps: {
item,
store: this.props.store
}
})
}
render() {
const { showInput } = this.state
const { list } = this.props.store
return (
<View style={{flex:1}}>
<View style={styles.heading}>
<Text style={styles.headingText}>My List App</Text>
</View>
{!list.length ? <NoList /> : null}
<View style={{flex:1}}>
{list.map((l, i) => {
return <View key={i} style={styles.itemContainer}>
<Text
style={styles.item}
onPress={this.addItemToList.bind(this, l)}>{l.name.toUpperCase()}</Text>
<Text
style={styles.deleteItem}
onPress={this.removeListItem.bind(this, l)}>Remove</Text>
</View>
})}
</View>
<TouchableHighlight
underlayColor='transparent'
onPress={
this.state.text === '' ? this.toggleInput.bind(this)
: this.addListItem.bind(this, this.state.text)
}
style={styles.button}>
<Text style={styles.buttonText}>
{this.state.text === '' && '+ New List'}
{this.state.text !== '' && '+ Add New List Item'}
</Text>
</TouchableHighlight>
{showInput && <TextInput
style={styles.input}
onChangeText={(text) => this.updateText(text)} />}
</View>
);
}
}

const NoList = () => (
<View style={styles.noList}>
<Text style={styles.noListText}>No List, Add List To Get Started</Text>
</View>
)

const styles = StyleSheet.create({
itemContainer: {
borderBottomWidth: 1,
borderBottomColor: '#ededed',
flexDirection: 'row'
},
item: {
color: '#156e9a',
fontSize: 18,
flex: 3,
padding: 20
},
deleteItem: {
flex: 1,
padding: 20,
color: '#a3a3a3',
fontWeight: 'bold',
marginTop: 3
},
button: {
height: 70,
justifyContent: 'center',
alignItems: 'center',
borderTopWidth: 1,
borderTopColor: '#156e9a'
},
buttonText: {
color: '#156e9a',
fontWeight: 'bold'
},
heading: {
height: 80,
justifyContent: 'center',
alignItems: 'center',
borderBottomWidth: 1,
borderBottomColor: '#156e9a'
},
headingText: {
color: '#156e9a',
fontWeight: 'bold'
},
input: {
height: 70,
backgroundColor: '#f2f2f2',
padding: 20,
color: '#156e9a'
},
noList: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
noListText: {
fontSize: 22,
color: '#156e9a'
},
})

export default TodoList


从 mobx-react/native 导入 observer;

使用 @observer 装饰器描述类,确保相关数组变化后组件独立地重渲染;

导入已经创建好的组件 NewItem。这是我们要增加新条目时转向的组件;

在 addListItem中,把 this.state.text 传入this.props.store.addListItem。在与输入框绑定的 updateText 中会更新this.state.text;

在 removeListItem 中调用 this.props.store.removeListItem 并传入条目;

在 addItemToList 中调用 this.props.navigator.push,传入条目和数组存储两个参数;

在 render 方法中,通过属性解构数据存储:

const { list } = this.props.store


8.在 render 方法中,也创建了界面,并绑定了类的方法

import React, { Component } from 'react'
import { View, Text, StyleSheet, TextInput, TouchableHighlight } from 'react-native'

class NewItem extends Component {
constructor (props) {
super(props)
this.state = {
newItem: ''
}
}
addItem () {
if (this.state.newItem === '') return
this.props.store.addItem(this.props.item, this.state.newItem)
this.setState({
newItem: ''
})
}
updateNewItem (text) {
this.setState({
newItem: text
})
}
render () {
const { item } = this.props
return (
<View style={{flex: 1}}>
<View style={styles.heading}>
<Text style={styles.headingText}>{item.name}</Text>
<Text
onPress={this.props.navigator.pop}
style={styles.closeButton}>×</Text>
</View>
{!item.items.length && <NoItems />}
{item.items.length ? <Items items={item.items} /> : <View />}
<View style={{flexDirection: 'row'}}>
<TextInput
value={this.state.newItem}
onChangeText={(text) => this.updateNewItem(text)}
style={styles.input} />
<TouchableHighlight
onPress={this.addItem.bind(this)}
style={styles.button}>
<Text>Add</Text>
</TouchableHighlight>
</View>
</View>
)
}
}

const NoItems = () => (
<View style={styles.noItem}>
<Text style={styles.noItemText}>No Items, Add Items To Get Started</Text>
</View>
)
const Items = ({items}) => (
<View style={{flex: 1, paddingTop: 10}}>
{items.map((item, i) => {
return <Text style={styles.item} key={i}>• {item}</Text>
})
}
</View>
)

const styles = StyleSheet.create({
heading: {
height: 80,
justifyContent: 'center',
alignItems: 'center',
borderBottomWidth: 1,
borderBottomColor: '#156e9a'
},
headingText: {
color: '#156e9a',
fontWeight: 'bold'
},
input: {
height: 70,
backgroundColor: '#ededed',
padding: 20,
flex: 1
},
button: {
width: 70,
height: 70,
justifyContent: 'center',
alignItems: 'center',
borderTopWidth: 1,
borderColor: '#ededed'
},
closeButton: {
position: 'absolute',
right: 17,
top: 18,
fontSize: 36
},
noItem: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
noItemText: {
fontSize: 22,
color: '#156e9a'
},
item: {
color: '#156e9a',
padding: 10,
fontSize: 20,
paddingLeft: 20
}
})

export default NewItem


如果你之前使用过MobX,那么相信在React Native使用同样简单。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: