前提
在之前專案中,我們一般是用mobx做資料狀態管理,本文嘗試使用新的方式--react hook,實現狀態管理,比較新舊方式的異同。
本文後面的所有內容的上下文都是在react專案中
歡迎指正,歡迎提出需要補充的地方。
複製程式碼
Mobx
先對mobx進行簡單介紹,如下圖可見,
從左往右順序檢視
1有且僅有action可以用於修改state,state變化會導致計算屬性(如果有的話)產生變化
2計算屬性的變化會導致reaction被觸發,產生一些副作用,例如更新UI
複製程式碼
why Mobx
我們的專案中使用mobx而不再使用setState原因有如下幾個(個人理解)
1 setSate 不是同步操作,當我們通過setstate修改state資料後,後面的邏輯立即取值是舊值,state的新值在下一次render時獲取到。
2 setState 不適合管理全域性的狀態。
複製程式碼
mobx狀態管理例項
mobx的使用方式也很簡單
1 安裝mobx相關的npm
2 宣告一個store類 存放我們需要的資料
複製程式碼
import { action, computed, observable } from "mobx"
class Store {
// 被觀察者,你可以理解成Vuex中的State,也就是說,宣告一些想要觀察的狀態,變數。
// 被觀察者可以是:JS基本資料型別、引用型別、普通物件、類例項、陣列和對映
@observable public num: number = 0;
@computed
public get addNum() {
// ...
}
// 使用@action 更改被觀察者
@action.bound
public add() {
// ...
}
}
複製程式碼
3 在最頂層使用provider注入所有的store,並且在需要監聽變化的地方的地方使用inject響應的資料,
並在元件宣告之前使用@observerble修飾符將元件改造為觀察者,只要它依賴的任何資料發生變化,就會重新整理元件.
複製程式碼
@inject("store")
@observer
class Example extends React.Component<{},{}> {
public render() {
return (
<h1>{this.props.store!.num}</h1>
)
}
}
複製程式碼
原理類似於一個使用@computed 宣告的store屬性,使用@observer修飾的元件會自動執行rebuild
複製程式碼
React components are (despite their name) not reactive out of the box. The @observer decorator from the mobx-react package fixes that by wrapping the React component render method in autorun, automatically keeping your components in sync with the state.
有興趣的同學可以康康這個簡單例子
複製程式碼
和這個十分鐘入門mobx
複製程式碼
使用react hook 實現全域性狀態管理
1 新建context
複製程式碼
const StateContext = createContext();
複製程式碼
2 設定StateContext.Provider的值為 useReducer
複製程式碼
const StateProvider = ({ reducer, initialState, children }) => (
<StateContext.Provider value={useReducer(reducer, initialState)}>
{children}
</StateContext.Provider>
);
複製程式碼
3 子元件(children) 使用dispath觸發reducer時 導致了Context 的 value的變化
導致了StateContext的value的更新,導致了元件的更新,由此實現 context reducer
->action->state-依賴於State的元件更新的資料傳遞
複製程式碼
有興趣的同學可以看看這個線上demo
基於hook擴充套件的的狀態管理工具 mobx-react-lite
同樣在observable物件內管理狀態,但不使用inject注入store,而是交給context管理
react hook狀態管理 在ssr中的問題
主要是從class元件到函式元件的過程中,需要注意的幾個不同點
1 getInitialProps class的靜態屬性->function元件的屬性
複製程式碼
Page.getInitialProps = async ctx => {
const res = await fetch('https://api.github.com/repos/zeit/next.js')
const json = await res.json()
return { stars: json.stargazers_count }
}
複製程式碼
2 原有的class元件中,store可以通過繼承baseStore,在baseStore中,通過傳入initState,
實現CS兩端的狀態同步,而函式元件中,沒有繼承的概念,需要尋找其他方法實現兩端資料同步
複製程式碼
總結
1 使用 context api + useReducer的方式,可以完成大部分狀態管理的需求,適合全域性狀態較為簡單的專案,但尚未解決ssr資料同步問題。
1 mobx 推出了 mobx-react-lite,更新了內部的工作機制,使用context做狀態管理,相對於原先的mobx-react的實現更為輕量(僅支援react 16.8.0+)
參考文章
mobx.js.org/getting-sta… 10分鐘入門mobx
juejin.im/post/59df1b… 為什麼我不再使用setstate
juejin.im/post/5d7ba9… react hook全域性狀態管理