本文寫於 2020 年 1 月 6 日react
示例代碼:https://github.com/AerospaceXu/hooks-soagit
React 社區最火的全局狀態管理庫一定是 Redux,可是 Redux 自己就是爲了大型管理數據而妥協設計的——這就會讓一些小一點的應用一旦用上 Redux 就變得複雜無比。github
後來又有了 Mobx,它對於小型應用的狀態管理確實比 Redux 簡單很多。但是不得不說 Mobx+React 簡直就是一個繁瑣版本的 Vue。redux
另外無論是 react-redux 仍是 mobx,他們使用的時候都很是複雜。須要你去組件函數或是組件類上修修改改,我我的從審美上來講就不是很喜歡。ide
後來用了 Angular 以後,我就開始對 SOA 產生好感,ng 的 Service 與依賴注入我都以爲很是漂亮。函數
Service 是 Angular 的邏輯複用形式,而且解決了共享狀態的問題,那 React 的自定義 Hook 能夠達到相似的效果嘛?spa
能夠,而且會比 Angular 更簡潔。設計
材料:useXxxx(自定義 hook)
, createContext
, useContext
。code
咱們作一個最簡單的計數器吧:一個 button,一個 panel,button 用來增長,panel 用來展現。get
const App: React.FC = () => { return ( <div> <Button /> <Panel /> </div> ); };
而後咱們來定義咱們的 Service:
// services/global.service.ts interface State { count: number; handleAdd: () => void; } export const GlobalService = createContext<State>(null);
咱們選擇讓一個 Context 成爲一個 Service,這是由於咱們能夠利用 Context 的特性來進行狀態共享。
而後咱們建立一個自定義 Hook,而且在 Context.provider
中傳入該 Root Service:
// services/global.service.ts export const useRootGlobalService = () => { const [count, setCount] = useState<number>(0); const handleAdd = useCallback(() => { setCount((n) => n + 1); }, []); return { count, handleAdd, }; };
接着咱們再建立一個自定義 Hook,讓咱們能夠隨時拿到該 Service:
// services/global.service.ts export const useGlobalService = () => useContext(GlobalService);
接着咱們就能夠運用了
// App.tsx import { GlobalService, useRooGlobalService } from './services/global.service'; const App: React.FC = () => { return ( <GlobalService.Provider value={useRooGlobalService()}> <div> <Button /> <Panel /> </div> </GlobalService.Provider> ); }; // Button.tsx import { useGlobalService } from '../services/global.service'; const Button: React.FC = () => { const { handleAdd } = useGlobalService(); return <button onClick={() => handleAdd()}>+</button>; }; // Panel.tsx import { useGlobalService } from '../services/global.service'; const Panel: React.FC = () => { const { count } = useGlobalService(); return <h2>{count}</h2>; };
(完)