由于我是android开发过渡到学习react-native的,所以对于一些web的状态管理方案不是很了解,比如说遇到多界面的异步刷新,直接使用回调的方式显得相当麻烦,到处留下接口,导致项目结构混乱,但在android中只需要使用广播,eventbus或者rxbus就可以解决的问题。我了解到react-redux这个东西,就是一个状态管理的解决方案,后来我发现,更多人推荐使用mobx去替换react-redux因为这个东西使用更简洁,更易于上手。当一个项目越来越庞大的时候,我们发现界面存在很多公共的逻辑,是不需要重复去写的,封装避免冗余代码这个工作是必不可少的,对比android,我们可以使用BaseActivity来封装公共逻辑,在react中最初我了解到mixin这个东西可以实现公共逻辑的封装,但是mixin不支持es6,所以最后采用了高阶组件的方式封装组件的base层,执行组件的公共逻辑。接下来详细介绍实现过程。
mobx基础
当我第一次看到mobx的时候我觉得它就是观察者模式,和android中的mvvm架构实现是差不多的。
mobx术语
主要是4个,可观察的状态,计算值,状态反应,触发动作
定义数据类
可观察的状态
通过@observable去标记变量,如对象,数组等,添加了可观察的功能。
1 2
| @observable count; @observable name;
|
根据状态得到计算值
1 2 3
| @computed get msg() { return `${this.name} say count is ${this.count}`; }
|
状态变化时的反应
autorun 方法需要传入数据类的实例,在可观察的变量被修改时调用
1 2 3
| autorun(() => { console.log(appState.msg); });
|
触发修改状态的动作
通过定义的动作方法修改状态的值
1 2 3 4 5 6
| @action add() { this.count += 1; } @action changeName(name) { this.name = name; }
|
整个数据类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| export default class AppState { @observable count; @observable name; @computed get msg() { return `${this.name} say count is ${this.count}`; } @action add() { this.count += 1; } @action changeName(name) { this.name = name; }
toJson() { return { count: this.count, name: this.name, } } }
|
在组件中使用
在index中注入数据类的实例对象,通过props传入到内部组件
1 2 3 4 5 6 7 8 9 10
| import AppState from './store/app-state'; class Root extends React.Component { render() { return ( <Provider appState={new AppState()}> <App /> </Provider> ); } }
|
在组件内监听,用@observer标记组件,@inject(‘appState’)注入数据类,通过props获取到数据类实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import React from 'react' import { observer, inject, } from 'mobx-react'; import PropTypes from 'prop-types'; import { AppState } from '../../store/app-state';
@inject('appState') @observer export default class TopicList extends React.Component { constructor() { super(); this.changeName = this.changeName.bind(this); }
componentDidMount() {
}
changeName(event) { this.props.appState.changeName(event.target.value); }
render() { return ( <div> <input type="text" onChange={this.changeName} /> <span>{this.props.appState.msg}</span> </div> ); } } TopicList.propTypes = { appState: PropTypes.instanceOf(AppState), };
|
利用高阶组件封装组件的base层
高阶组件Higher Order Component简称HOC,是一个使用函数来实现的类工厂,接收一个React.Component的参数,这个参数必须传,我们可以定义为WrappedComponent,代表被包裹的组件,返回一个React.Component的对象,就是包裹后的新组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| export const HighOrderComponent = (WrappedComponent, title) => { return class HOC extends React.Component { constructor(props) { super(props); this.state = { username: '' } } componentWillMount() { let username = localStorage.getItem('username'); this.setState({ username: username }); } render() { return( <div> <View>{title}</View> <WrappedComponent {...this.props} username={this.state.username}></WrappedComponent> </div> ) } } }
|
我们可以在这个类中操作props,对props的增删改查,可以通过Refs访问到组件实例,对state做处理,也可以用其他的组件包裹WrappedComponent。作为组件的base层,在这里处理公共逻辑,使用的时候传入被包裹的组件。
1 2 3 4 5 6 7 8 9 10
| class Index extends React.Component { render() { return( <View> <Text>Hi {this.props.username}</Text> </View> ) } } export const HighOrderIndex = HighOrderComponent(Index, 'Index title');
|