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