0%

react-native-mobx和高阶组件


由于我是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;
}

// 返回json格式化数据
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() {
// do something here

}

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 {
// 公共state初始化
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');