简单的介绍一下mobx
MobX 是透明的函数响应式编,它主要优点使得状态管理变得简单和可扩展(这一点接下来我会简单的对比一下redux);
React 和 MobX 是一对强力组合。React 通过提供机制把应用状态转换为可渲染组件树并对其进行渲染。而MobX提供机制来存储和更新应用状态供 React 使用。官网传送redux和mobx对比
两者都是状态管理库,用来管理应用的内部状态,所以在我们项目中,完全可以相互替代,我简单的对比一下开发成本:
这里我以标准的项目实践对比,在我们日常项目开发中,采用redux库,下图是我们一个业务组件的目录结构
通常我们如果我们需要通过一个接口获取列表数据,需要在多个文件中定义一整套变量,项目业务复杂开发不规范,就会出现以下现象:反过来,我们看下重构之后,采用mobx的文件目录结构
具体实现方式,下文会详细介绍,以上仅做简单对比!
开始搭建mobx项目
首先,该项目是采用webpack4打包器,对webpack配置不熟悉的同学,可参考一下掘金上Better_man同学的优秀讲解webpack4.x最详细入门讲解!
现在完事具备,只欠mobx,开始我们的mobx之旅~
Step 1: 安装依赖文件
npm i mobx mobx-react -D
Step 2: 组件以及模块划分
定义好目录结构以及模块拆分很重要,使得我们在开发过程中思路清晰,代码整洁;
Step 3: 划分领域store,并定义可观察的状态
我们在store文件夹下新建,movieStore.js文件,如下图
接下来,如何定义可观察的状态呢,我们看代码:
import {observable, action, computed, runInAction} from 'mobx';
import Api from '../api/movie';
export class movieStore {
@observable movieList = [];
@observable state = 'pending';
constructor(rootStore) {
this.rootStore = rootStore;
this.fetchMovies = this.fetchMovies.bind(this);
this.setPrice = this.setPrice.bind(this);
}
@action
async fetchMovies() {
this.state = 'pending';
this.movieList = [];
try {
const subjects = await Api.getMovie();
//await之后更改状态
runInAction(() => {
this.state = 'Done';
this.movieList = subjects;
});
} catch (e) {
runInAction(() => {
this.state = "error";
});
}
}
}
上面我们定义了2个状态,movieList:电影列表,state: 接口的请求状态,在其变量前面加上@observable 使其可观察,同时定义action,请求接口并改变初始状态,以上代码写法需要开启装饰器,(1)添加装饰器依赖
npm i babel-plugin-transform-decorators-legacy -D
(2).babelrc文件添加配置
"plugins": ["transform-decorators-legacy"]
Step 4: 创建视图以响应状态的变化
首先,在views目录下,新建movie文件来存放movie组件相关文件,在movie文件夹下创建index.jsx, 定义observer包裹React组件的高级组件
import React, {Component} from 'react';
import {observer} from "mobx-react";
@observer
export default class Movie extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>movie</div>
)
}
}
Step 5: 全局注册并注入store实例
一个经常被问到的问题就是,如何不使用单例来组合多个 stores 。它们之间如何通信呢? 答案就是,创建一个 RootStore 来实例化所有 stores ,并共享引用; 示例: store/index.js
import {configure, observable, computed} from 'mobx';
import {movieStore} from './movieStore';
import {loginStore} from './loginStore';
configure({enforceActions: 'observed'});
export default class store {
@observable movieStore;
@observable loginStore;
constructor() {
this.movieStore = new movieStore(this);
this.loginStore = new loginStore(this);
}
}
完成多个领域store的组合,使用
<Provider rootStore={new RootStore()}><App /></Provider>
方式注入到组件库中。接下来就是在我们的视图组件中引入单个store,视角再次切换回到Movie组件,完善代码:
import React, {Component} from 'react';
import {inject, observer} from "mobx-react";
import { Table } from 'antd';
@inject((stores) => {
return {
movieStore: stores.store.movieStore
}
})
@observer
export default class Movie extends Component {
constructor(props) {
super(props);
}
async componentDidMount(){
const {movieList,fetchMovies} = this.props.movieStore;
if (movieList.length > 0)
return;
await fetchMovies();
}
render() {
const {state, movieList, setPrice, price} = this.props.movieStore;
const columns = [{
title: '名称',
dataIndex: 'title',
render: text => <a href="javascript:;">{text}</a>,
}, {
title: '豆瓣评分',
dataIndex: 'rating',
}, {
title: '年份',
dataIndex: 'year',
}, {
title: '描述',
dataIndex: 'original_title'
}];
const data = movieList.map(item => ({
id: item.id,
key: item.id,
title: item.title,
rating: item.rating.average,
year: item.year,
original_title: item.original_title
}));
return (
<div>
<Table loading={state === 'pending'} columns={columns} dataSource={data} />
</div>
)
}
}
通过@inject,注入我们需要的store,注入之后我们可以在组件props中访问可观察属性和方法; 这里我使用antd UI库的table组件作为数据展示,有兴趣可去Ant Design官网
结语
以上是简单的mobx项目搭建,项目源代码请戳react-mobx,新手上路,以上都属于自己学习mobx的个人见解,如有理解错误之处,请各位大佬指出!