擺脫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";
@observerexport 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
}
})@observerexport 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的個人見解,如有理解錯誤之處,請各位大佬指出!

來源:https://juejin.im/post/5be3a510f265da61171c3767

相關文章