mobx、mobx-react和mobx-react-lite新手入門

1. 寫在前面

本文會介紹mobxmobx-reactmobx-react-lite的基本使用,還有配合react context api的使用,都是api的入門使用,不涉及源碼剖析。react

2. 什麼是Mobx?

  1. Simple, scalable state management
  2. MobX is a battle tested library that makes state management simple and scalable by transparently applying functional reactive programming (TFRP)

Mobx是簡單、可擴展的狀態管理庫。是通過戰鬥洗禮的庫,經過透明的函數響應式編程使狀態管理變得更加簡單且可擴展。說明Mobx足夠可靠,可放心在項目中使用。git

上圖所示,Mobx是經過event事件調用action,修改observal state數據,進而觸發computed,使其自動更新數據,Reactions是對state的改變作出的反應,以此更新視圖,這是Mobx的核心所在github

3. mobx的使用

mobx 爲 6.x 版本,經常使用api的使用ajax

3.1 使用makeObservable

import {makeObservable,observable,action,computed,autorun,reaction,when} from "mobx";
// 建立store
const store = makeObservable({
    count:1,
    get double(){return this.count * 2;},
    // 定義action
    increment(){this.count += 1;},
    decrement(){this.count -= 1;},
},{
    count: observable,//須要響應的屬性
    double: computed,//計算屬性
    increment: action,//action
    decrement: action,
});
class MobxDemo {
  handleRefresh(){
    this.container.innerHTML=`
      count: ${store.count}
      double count: ${store.double}
    `
;
  }
  init() {
    this.handleRefresh();
    this.increaseBtn.addEventListener("click",()=>{store.increment();});
    this.decreaseBtn.addEventListener("click",()=>{store.decrement();});
    // autorun相似於react hooks中的useEffect
    // 當observable響應屬性被更新時,autorun當即被調用一次
    autorun(()=>{this.handleRefresh();});
    // 相似Vue中的watch觀察
    reaction(
      ()=>store.count, // 指定觀察count屬性
      (currentVal, oldVal)=>{console.log(`current: ${currentVal}, old: ${oldVal}`);}
    );
    // 條件響應
    when(
      ()=>store.count < 0,
      ()=>{console.log("...");}
    );
  }
}
const mobxDemo = new MobxDemo();
mobxDemo.init();
複製代碼

3.2 使用makeAutoObservable

相比makeObservable,makeAutoObservable就簡化多了,無需再手動指定observable、action、computednpm

import {makeAutoObservable,autorun,runInAction} from "mobx";
// 直接使用makeAutoObservable
const store = makeAutoObservable({
  count1,
  get double(){return this.count*2;},
  increment(){this.count+=1;},
  decrement(){this.count-=1;},
  // 在 MobX 中,無論是同步仍是異步操做,均可以放到 action 中,
  // 只是異步操做在修改屬性時,須要將賦值操做放到 runInAction 中。
  async asyncDecreament() {
    // 模擬ajax獲取數據
    const count = await new Promise((resolve)=>{
      setTimeout(()=>resolve(1), 50);
    });
    // 獲取數據後,將賦值操做放到 runInAction 中
    runInAction(()=>{this.count -= count;});
  },
});
複製代碼

3.3 使用 6.x 版本以前的 decorator 裝飾器寫法

import {observable,action,computed} from "mobx";
class Store {
  @observable count=0;
  constructor(){makeObservable(this);}
  @computed get double(){return this.count * 2;}
  @action increment(){this.count++;}
  @action decrement(){this.count--;}
}
const store = new Store();
複製代碼

4. mobx-react-lite的使用

mobx-react-litemobx-react的輕量化版本,在mobx-react@6版本中已經包含了mobx-react-lite,可是若是隻在函數式組件中使用,推薦使用輕量化的mobx-react-lite編程

4.1 父組件使用useLocalObservable建立store

import React,{createContext} from "react";
import {observer,useLocalObservable} from "mobx-react-lite";
import Child1 from "@/component/Child1";
import Child2 from "@/component/Child2";
import Child3 from "@/component/Child3";

export const Context = createContext(null);

const Parent=()=>{
  // 'useLocalStore' is deprecated, use 'useLocalObservable' instead.
  const storeContext = useLocalObservable(()=>({
    count1,
    get double(){return this.count*2;},
    increase(){this.count+=1;},
    decrease(){this.count-=1;},
  }));
  return (
    <Context.Provider value={storeContext}>
      <Child1 />
      <Child2 />
      <Child3 />
    </Context.Provider>

  );
};
export default observer(Parent);
複製代碼

4.2 子組建爲function組件(使用Context)

import React, {useContext,useEffect} from "react";
import {observer} from "mobx-react-lite";
import {toJS,reaction,when} from "mobx";
import {Context} from "@/App";
const Child1=()=>{
  const store=useContext(Context);
  useEffect(()=>{
    console.log("store:", toJS(store));
    reaction(
      ()=>store.count,
      (cur, pre)=>{console.log(`cur: ${cur}, pre: ${pre}`);}
    );
    when(
      ()=>store.count < 0,
      ()=>{console.log("...");}
    );
  }, [store]);
  // [mobx-react-lite] 'useObserver(fn)' is deprecated
  // Use `<Observer>{fn}</Observer>`instead, or wrap the entire component in `observer`
  return(
    <div>
      count: {store?.count}|double:{store?.double}    
      <button onClick={()=>store.increase()}>increase</button>
      <button onClick={()=>store.decrease()}>decrease</button>
    </div>

  );
};
export default observer(Child1);
複製代碼

4.3 子組建爲function組件(不使用Context)

不使用 Context,就要用到mobx-react,看 5.3 部分api

4.4 子組件爲 class 組件

經過Context.Consumer組件獲取到storemarkdown

import React,{Component} from "react";
import {Observer} from "mobx-react-lite";
import {Context} from "@/App";
class Child3 extends Component {
  render(){
    return(
      <Context.Consumer>
        {(store)=>(
          <div>
            <Observer>{()=><div>count:{store?.count}</div>}</Observer>
            <button onClick={()=>store.increase()}>increase</button>
            <button onClick={()=>store.decrease()}>decrease</button>
          <div/>
        )}
      </Context.Consumer>
    );
  }
}
export default Child3;
複製代碼

5. mobx-react的使用

5.1 父組件用mobx-react提供的Provider組件向下傳遞store

import React from "react";
import {Provider} from "mobx-react";
import {useLocalObservable} from "mobx-react-lite";
import Child1 from "@/component/Child1";
import Child2 from "@/component/Child2";
const Parent=()=>{
  // 也可使用mobx建立一個store
  const storeContext = useLocalObservable(()=>({
    count:1,
    get double(){return this.count*2;},
    increase(){this.count+=1;},
    decrease(){this.count-=1;},
  }));
  return (
    <Provider store={storeContext}>
      <Child1 />
      <Child2 />
    </Provider>

  );
};
export default observer(Parent);
複製代碼

5.2 子組件爲 class 組件

import React from "react";
import {observer,inject} from "mobx-react";
@inject("store")
@observer
class Child1 extends React.Component {
  render()(
    <>
      count:{store?.count}|double:{store?.double}
      <button onClick={()=>store.increase()}>increase</button>
      <button onClick={()=>store.decrease()}>decrease</button>
    </>

  )
}
export default observer(Child1);
複製代碼

5.3 子組件爲 function 組件

import React from "react";
import {inject,observer} from "mobx-react";
const Child2=({store})=>{
  return(
    <>
      count:{store?.count}|double:{store?.double}
      <button onClick={()=>store.increase()}>increase</button>
      <button onClick={()=>store.decrease()}>decrease</button>
    </>

  );
};
export default inject("store")(observer(Child2));
複製代碼

6. 參考資料

  1. MobX 上手指南,寫 Vue 的感受?
  2. mobx-react-lite 基於 React Hook API 輕量級狀態管理
  3. 初探mobx-react-lite
  4. mobx-npm
相關文章
相關標籤/搜索