First, after much thought and consideration, Mobx was chosen as the status management tool for the new project. The main reasons were that Mobx implemented responsive programming, the code was more lightweight and simple, and the natural support for independent coexistence of multiple stores.
This is the first day of my participation in the August Challenge. For details, see:August is more challenging
In fact, it takes a lot of struggle and a lot of thinking to pick the one you like best. This is probably the best practice for data flow in large, complex projects. With the theoretical guidance of the big guy, MY confidence doubled immediately.
Start by designing the domain model
Let’s take a simple e-commerce system as an example. For example, we need to pay attention to several areas:
- User (saves information about the current user)
- Orders (save current order information)
- Notifications (need to display the latest notification information, either from the server side or from the user page for some actions following the order)
We want to implement these interactions:
- Add a record to the notification Store after clicking the order successfully
- Notice or order can be displayed only after the user has logged in (authenticated).
We can design the store hierarchy according to the requirements:
- Global-store (provides authentication status, token information, and notification)
- User (including user details and login and logout methods)
- The order
Note: We have a convention that child stores can only interact with parent stores, no sibling or cross-reference, and if there is a need for cross-invocation, some of the data or state should be promoted to a common parent.
At this point, we’re just talking about the design, but let’s demonstrate the implementation details in code
The project of actual combat
First configure the public 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();
Copy the code
Then the 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);
// Inject the public 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();
Copy the code
And then 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();
Copy the code
It is better to configure the store entry file with the contextAPI to provide the 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);
Copy the code
Component consumption:
import {StoreProvider} from './store/index'
<StoreProvider>
<App />
</StoreProvider>
Copy the code
The last
Thank you for reading. If you have any questions, please leave a comment. Thank you!