擺脫redux繁瑣操作,搭建mobx框架

colaman發表於2018-11-08

簡單的介紹一下mobx

MobX 是透明的函式響應式編,它主要優點使得狀態管理變得簡單和可擴充套件(這一點接下來我會簡單的對比一下redux);

mobx
React 和 MobX 是一對強力組合。React 通過提供機制把應用狀態轉換為可渲染元件樹並對其進行渲染。而MobX提供機制來儲存和更新應用狀態供 React 使用。官網傳送

redux和mobx對比

兩者都是狀態管理庫,用來管理應用的內部狀態,所以在我們專案中,完全可以相互替代,我簡單的對比一下開發成本:

這裡我以標準的專案實踐對比,在我們日常專案開發中,採用redux庫,下圖是我們一個業務元件的目錄結構

擺脫redux繁瑣操作,搭建mobx框架

擺脫redux繁瑣操作,搭建mobx框架
通常我們如果我們需要通過一個介面獲取列表資料,需要在多個檔案中定義一整套變數,專案業務複雜開發不規範,就會出現以下現象:

擺脫redux繁瑣操作,搭建mobx框架

反過來,我們看下重構之後,採用mobx的檔案目錄結構

擺脫redux繁瑣操作,搭建mobx框架

具體實現方式,下文會詳細介紹,以上僅做簡單對比!

開始搭建mobx專案

首先,該專案是採用webpack4打包器,對webpack配置不熟悉的同學,可參考一下掘金上Better_man同學的優秀講解webpack4.x最詳細入門講解

現在完事具備,只欠mobx,開始我們的mobx之旅~

Step 1: 安裝依賴檔案

npm i mobx mobx-react -D
複製程式碼

Step 2: 元件以及模組劃分

擺脫redux繁瑣操作,搭建mobx框架

定義好目錄結構以及模組拆分很重要,使得我們在開發過程中思路清晰,程式碼整潔;

Step 3: 劃分領域store,並定義可觀察的狀態

我們在store資料夾下新建,movieStore.js檔案,如下圖

擺脫redux繁瑣操作,搭建mobx框架

接下來,如何定義可觀察的狀態呢,我們看程式碼:

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的個人見解,如有理解錯誤之處,請各位大佬指出!

相關文章