使用Mobx管理React應用的狀態

首先,通過深思熟慮、反覆思考決定選擇Mobx做爲新項目的狀態管理工具,緣由主要爲:Mobx貫徹了響應式編程,代碼更加的輕量簡潔,且自然支持多store獨立共存。react

這是我參與8月更文挑戰的第1天,活動詳情查看:8月更文挑戰編程

其實,想說技術選型須要經歷無數的掙扎和反覆的思考拿捏,而後選出那個你最喜歡的。固然參考了阿里巴巴大佬的文章:這多是大型複雜項目下數據流的最佳實踐。有了大佬的理論指導,我頓時信心倍增。api

從設計領域模型開始

咱們以簡易的電商系統爲例,好比須要咱們關注幾個領域:服務器

  • 用戶(保存當前用戶的信息)
  • 訂單(保存當前訂單的信息)
  • 通知(須要顯示最新的通知信息,可能來自服務器端,也可能來自用戶頁面的一些操做以下了訂單)

咱們想實現這麼幾個交互:markdown

  • 點擊下單成功後向通知store裏添加一條記錄
  • 用戶登錄(鑑權後)方可顯示通知或訂單。

根據需求咱們能夠設計store的層級:ide

  • global-store(提供鑑權狀態、token信息、通知)
    • 用戶(包含用戶詳情信息,以及登錄、登出方法)
    • 訂單

注意:咱們約定:子級store只能跟父store交互,不能夠同級或交叉引用,若是確實有交叉調用的需求,應該把其中的某些數據或狀態提高到共同的上級。工具

到這裏,咱們還只是討論設計,接下來咱們用代碼來演示一下實施細節oop

項目實戰

首先配置公共store(share-storepost

// share-store
import { makeObservable, observable, action } from "mobx"

type LoginStatus = undefined|true|false;
export class ShareStore {
    @observable authStatus:boolean = false;
    @observable token:string = "";
    @observable notifyList:Array<string> = [];

    constructor() {
        makeObservable(this);
    }

    //update loginStatus
    @action
    updateAuthStatus(state:boolean) {
        this.authStatus = state;
    }
    @action 
    updateToken(token:string){
        this.token = token;
    }
    @action addNotify(notify:string){
        this.notifyList.push(notify)
    }
}
export const shareStore = new ShareStore();
複製代碼

接着是order-store:ui

//order-store
import { makeObservable, observable, action } from "mobx"
import {shareStore,ShareStore} from '../shared-store'
type orderStatusType = "none"|"progressing"|"done"
export class OrderStore {
    @observable orderStatus:orderStatusType = "none"
    @observable orderName:string = "";
    @observable orderType:"Book"|"Computer"|"" = "";
    @observable rootStore:ShareStore;
    
    constructor() {
        makeObservable(this);
        //將公共store注入
        this.rootStore = shareStore;
    }
    @action
    updateOrderStatus(state:orderStatusType) {
        this.orderStatus = state;
    }
    @action
    updateOrderInfo(state:any) {
        this.orderType = state.type;
        this.orderName = state.name;
    }
    @action
    doOrder(payload:any){
        //api request
        //....
        const msgName = "A new order occurs";
        this.rootStore.addNotify(msgName);
    }
}
export const orderStore = new OrderStore();
複製代碼

再而後是user-store:

//user-store
import { makeObservable, observable, action } from "mobx"
import {shareStore,ShareStore} from '../shared-store'
type UserInfoType = {
    name:string,
    gender:string,
    level:number
}
export class UserStore {
    @observable userInfo:UserInfoType = {
        name:"",
        gender:"",
        level:0
    }
    @observable rootStore:ShareStore;
    
    constructor() {
        makeObservable(this);
        this.rootStore = shareStore;
    }
    @action
    updateUserInfo(state:UserInfoType) {
        this.userInfo = state;
    }
    @action 
    doLogin(userName:string,password:string) {
        //Api request send
        //....
        const result = {
            name:"Andrew",
            gender:"male",
            level:100
        }
        this.updateUserInfo(result)
    }
    @action
    doLogout(){
        //get token 
        const token = this.rootStore.token;
        //Api request send
        //....
    
        this.rootStore.updateAuthStatus(false)
    }
}
export const userStore = new UserStore();
複製代碼

最好咱們配置store的入口文件,搭配contextAPI提供provider:

//index.ts
import {shareStore,ShareStore} from './shared-store'
import {orderStore,OrderStore} from './order/order'
import {userStore,UserStore} from './user/user'
import {createContext, useContext} from 'react'

interface StoreType {
    shareStore:ShareStore,
    orderStore:OrderStore,
    userStore:UserStore
}

const store:StoreType = {
    shareStore,
    orderStore,
    userStore
}
const Context = createContext<Partial<StoreType>>({});


export const StoreProvider:React.FunctionComponent<{}> = ({ children }) => {
    return (<Context.Provider value={store}>{children}</Context.Provider>)
};
export const useStore = () => useContext(Context);
複製代碼

組件消費:

import {StoreProvider} from './store/index'

<StoreProvider>
  <App />
</StoreProvider>
複製代碼

最後

感謝閱讀,若有任何疑問歡迎留言指教,謝謝!

相關文章
相關標籤/搜索