mobx-react-lite + Context 使用不完全指南
mobx-react-lite
是mobx-react
的輕量版,增加了對函數式組件hooks
的支持
隨着 React Hooks
的推出,讓我們在不編寫 class 的情況下使用 state 以及其他的 React 特性,現在項目中使用Hooks的函數式組件日益增多,而多個組件之間的狀態管理變得日益複雜。
那麼在多層級的函數式組件中如何維護好 state
呢?
React Hooks 自帶的 useReducer 配合 Context 進行狀態管理
使用過Redux的就會非常熟悉了,useReducer
可以看成Redux的簡版,使用過程中需要通過 Context
將 useReducer
返回的 state
dispatch
傳遞下去,子孫組件通過 useContext
獲取到 state
dispatch
,通過 dispatch
修改狀態,使得組件更新
這種方式針對一些沒有複雜狀態的層級組件 和 熟悉 Redux 的同學比較友好,而針對複雜的表單狀態管理和大量異步操作的層級組件顯得有點力不從心。
mobx-react-lite 配合 Context 進行狀態管理
習慣 mobx 風格進行狀態管理的開發者會更傾向於這一種,不管是複雜狀態的管理還是異步操作都支持的很好。
下文主要結合 mobx
、mobx-react-lite
、Context
進行示例描述。(我要貼代碼了)
- 創建
store
// store/index.js
import { observable, action, computed } from 'mobx'
export class CounterStore {
@observable
count = 0
@action
increment() {
this.count++
}
@action
decrement() {
this.count--
}
@computed
get doubleCount() {
return this.count * 2
}
}
export class ThemeStore {
@observable
theme = 'light'
@action
setTheme(newTheme) {
this.theme = newTheme
}
}
這一步創建了兩個 store 並導出
- 創建
Context
// contexts/index.js
import React from 'react';
import { CounterStore, ThemeStore } from '../store';
export const StoresContext = React.createContext({
counterStore: new CounterStore(),
themeStore: new ThemeStore()
})
創建 StoresContext
並導出,那麼後代組件在 useContext
時便可以得到包含 CounterStore
ThemeStore
實例的對象
- 由於多組件都需要使用
useContext
,我們將其封裝爲hook
函數
// hooks/useStores.js
import React from 'react'
import { StoresContext } from '../contexts'
export const useStores = () => React.useContext(StoresContext)
通過 useStores
獲取 React.createContext
給的初始值對象(前提是沒有 StoresContext.Provider
組件,如果使用了該組件,則拿到的是 StoresContext.Provider
的 value
屬性對應的值)
- 後代組件獲取 store 並調用 action 修改狀態,使用
mobx-react-lite
更新組件
import React from 'react';
import { useStores } from '../../hooks/user-store';
import { useObserver } from 'mobx-react-lite';
const Counter = () => {
let store = useStores(); // 獲取store
const {counterStore, themeStore} = store;
const handleIncrement = () => {
counterStore.increment();
}
const handleDecrement = () => {
counterStore.decrement();
}
return useObserver(() => (
<div>
<p>count: {counterStore.count}</p>
<p>theme: {themeStore.theme}</p>
<button onClick={handleIncrement}>add</button>
<button onClick={handleDecrement}>dec</button>
</div>
))
}
export default Counter;
通過 useStores 獲取state進行展示,調用 action 修改 store 狀態,會被 useObserver 監聽到,並更新組件
總結
這裏只用到 mobx-react-lite
中的 useObserver
API,其他的常用 API 還有 useLocalStore observer
等,文檔在 mobx-react
Using MobX with React Hooks and TypeScript
這篇文章做了詳細實例,其中使用了 useLocalStore observer
並配合 Typescript 做了優化