什么是Mobx

一个简单,可拓展的状态管理工具

安装

npm install mobx --save

核心概念

flow.png

State(状态)

状态是驱动应用的数据,状态的改变会影响视图。

import {observable, autorun} from 'mobx';
var todoStore = observable({
    /* 一些观察的状态 */
    todos: []
});

Derivations(衍生)

任何源自状态并且不会再有任何进一步的相互作用的东西就是衍生。

import {observable, autorun} from 'mobx';
var todoStore = observable({
    /* 一些观察的状态 */
    todos: [],
    /* 衍生值 */
    get completedCount() {
        return this.todos.filter(todo => todo.completed).length;
    }
});
注意:衍生值必须是纯函数

Actions(动作)

动作是一段可以改变状态的代码。用户事件、后端数据推送、预定事件、等等。

使用原则

MobX 支持单向数据流,也就是动作改变状态,而状态的改变会更新所有受影响的视图。

1、当状态改变时,所有衍生都会进行原子级的自动更新。
2、所有衍生默认都是同步更新。这意味着例如动作可以在改变状态之后直接可以安全地检查计算值。
3、计算值 是延迟更新的。任何不在使用状态的计算值将不会更新,直到需要它进行副作用(I / O)操作时。 如果视图不再使用,那么它会自动被垃圾回收。
4、所有的计算值都应该是纯净的。它们不应该用来改变状态。

举个例子:

import { observable,computed, action } from 'mobx';
class ObservableTodoStore {
    //定义可响应状态
    @observable todos = [];
    @observable pendingRequests = 0;
    
    //衍生值
    @computed get completedTodosCount() {
        return this.todos.filter(
            todo => todo.completed === true
        ).length;
    }

    @computed get report() {
        if (this.todos.length === 0)
            return "<none>";
        return `Next todo: "${this.todos[0].task}". ` +
            `Progress: ${this.completedTodosCount}/${this.todos.length}`;
    }
    
    //动作
    @ction
    addTodo(task) {
        this.todos.push({
            task: task,
            completed: false,
            assignee: null
        });
    }
}

const observableTodoStore = new ObservableTodoStore();

使用装饰器@

装饰器会看起来更友好一些,使用babel-preset-mobx

npm install --save-dev babel-preset-mobx

安装后在package.json中配置

52123F5E-50A3-441f-B1FB-FF49C2F7D948.png

解决异步更新state

class Store {
    //定义状态
    @observable listData = []
    @observable state = "pending";
    
    //异步行为修改状态,比如向服务器请求数据
    @action
    async fetchProjects() {
        this.state = "pending"
        try {
            const filteredProjects = await ajaxData();
            // await 之后,再次修改状态需要动作:
            runInAction(() => {
                this.state = "done"
                this.listData = filteredProjects
            })
        } catch (error) {
            runInAction(() => {
                this.state = "error"
            })
        }
    }
}

runInAction是一个工具函数。只在动作中运行回调函数中状态修改的部分,而不是为整个回调创建一个动作。 这种模式的优势是它鼓励你不要到处写 action,而是在整个过程结束时尽可能多地对所有状态进行修改。

一个完整的例子:

整个应用状态管理入口:

import React from 'react';
import ReactDOM from 'react-dom';
import { ConfigProvider } from 'antd';
import App from './App';
import zhCN from 'antd/es/locale/zh_CN';
import { Provider } from 'mobx-react';
import stores from '@/stores'

ReactDOM.render(<ConfigProvider locale={zhCN}>
    <Provider {...stores}><App /></Provider>
</ConfigProvider>, document.getElementById('root'));

store统一管理:

import permissionStore from './permission';
const stores={
    permissionStore
}
export default stores;

定义单文件store

import { observable, action, runInAction } from 'mobx';
import $http from '@/utils/http';
class PermissionStore {
    @observable menus = [];
    @action
    async fetchMenus() {
        try {
            let menus = await this.handleFetchMenus();
            runInAction(() => {
                this.menus = menus;
            })
        } catch (error) {
            
        }
    }
    handleFetchMenus() {
        return $http("/permission/menuList").then(resp => {
            if (resp && resp.items && resp.items.length) {
                return resp.items;
            }
        });
    }
}
export default new PermissionStore();

组件绑定

import React from 'react';
import { observer, inject } from 'mobx-react'

@inject('permissionStore');//引入对应的store
@observer
class SideMenu extends React.Component {
    constructor(props) {
        super(props);
    }
    componentDidMount() {
        const { permissionStore } = this.props;//从props中获取store
        permissionStore.fetchMenus();//store中的异步action
    }
    //生成菜单栏
    renderMemu = () => {
        let { menus } = this.props.permissionStore;//获取状态,此时数据是异步从服务器获取后更新的数据状态
        return (
           ...
        )
    }
    render() {
        return (
            {this.renderMemu()}
        )
    }
}
export default SideMenu

mobx涉及的核心概念就三个,State(状态),Derivations(衍生值)和Actions(动作),使用起来非常简单和清晰,可以快速上手,是一个不错的状态管理工具,github star有21K。


沉默术士
29 声望1 粉丝