使用Mobx管理React应用的状态

·  阅读 1035

首先,经过深思熟虑、反复思考决定选择Mobx作为新项目的状态管理工具,原因主要为:Mobx贯彻了响应式编程,代码更加的轻量简洁,且天然支持多store独立共存。

这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战

其实,想说技术选型需要经历无数的挣扎和反复的思考拿捏,然后选出那个你最喜欢的。当然参考了阿里巴巴大佬的文章:这可能是大型复杂项目下数据流的最佳实践。有了大佬的理论指导,我顿时信心倍增。

从设计领域模型开始

我们以简易的电商系统为例,比如需要我们关注几个领域:

  • 用户(保存当前用户的信息)
  • 订单(保存当前订单的信息)
  • 通知(需要显示最新的通知信息,可能来自服务器端,也可能来自用户页面的一些操作如下了订单)

我们想实现这么几个交互:

  • 点击下单成功后向通知store里添加一条记录
  • 用户登陆(鉴权后)方可显示通知或订单。

根据需求我们可以设计store的层级:

  • global-store(提供鉴权状态、token信息、通知)
    • 用户(包含用户详情信息,以及登陆、登出方法)
    • 订单

注意:我们约定:子级store只能跟父store交互,不可以同级或交叉引用,如果确实有交叉调用的需求,应该把其中的某些数据或状态提升到共同的上级。

到这里,我们还只是讨论设计,接下来我们用代码来演示一下实施细节

项目实战

首先配置公共store(share-store

// 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:

//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>
复制代码

最后

感谢阅读,如有任何疑问欢迎留言指教,谢谢!

分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改