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

簡單的介紹一下mobx

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

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

redux和mobx對比

二者都是狀態管理庫,用來管理應用的內部狀態,因此在咱們項目中,徹底能夠相互替代,我簡單的對比一下開發成本:java

這裏我以標準的項目實踐對比,在咱們平常項目開發中,採用redux庫,下圖是咱們一個業務組件的目錄結構 react

一般咱們若是咱們須要經過一個接口獲取列表數據,須要在多個文件中定義一整套變量,項目業務複雜開發不規範,就會出現如下現象:

反過來,咱們看下重構以後,採用mobx的文件目錄結構webpack

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

開始搭建mobx項目

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

如今完事具有,只欠mobx,開始咱們的mobx之旅~web

Step 1: 安裝依賴文件

npm i mobx mobx-react -D
複製代碼

Step 2: 組件以及模塊劃分

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

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

咱們在store文件夾下新建,movieStore.js文件,以下圖redux

接下來,如何定義可觀察的狀態呢,咱們看代碼:api

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的我的看法,若有理解錯誤之處,請各位大佬指出!

相關文章
相關標籤/搜索