一年前,2018 年 9 月左右, React hooks 剛發佈,那時 hooks 還不是穩定 Api,只能在 16.7.0-alpha.0 版本能用。那時我就預感到,基於 hooks 狀態管理解決方案會逐漸崛起,當時我基於 hooks 建立一個我認爲理想的狀態管理庫:stamen。react
我還寫過一篇文章介紹它:多是基於 Hooks 和 Typescript 最好的狀態管理工具。git
我以前說過,我想要這樣的一個狀態管理庫:github
因此我建立了 Stamen,Stamen 相比 Redux 更加簡潔,對 TypeScript 支持度更好。一年多過去了,也在幾個小項目中實踐過,發現並無很好知足個人兩個指望。web
Stamen 的 Api 借鑑了 dva 和 rematch,致使了它沒有脫離 Redux 的影子,依然有 state、reducers、effects、dispatch、selector 等概念,能夠說沒有完全 Hooks 化,特別是 reducers 處理同步和 effects 處理反作用讓我以爲特別扭。chrome
一年後,我建立了更加完全 Hooks 化的狀態管理庫:Stook。npm
Stook,中文翻譯是谷堆,命名靈感來自 store、hooks 兩個單詞的組合,一個極簡主義的 React 狀態管理庫。編程
咱們看看 Stook 用法有多麼的簡單,下面是一個經典的 Counter 組件,展現了 stook
的最基本用法:redux
import React from "react"; import { useStore } from "stook"; function Counter() { const [count, setCount] = useStore("Counter", 0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); } 複製代碼
Stook 最核心的 Api 就是 useStore
,也許你發現了,它和 useState
很是像,實際上,useStore
除了多了一個參數之外,其餘用法如出一轍。瀏覽器
Stook 極簡之處在於它的用法跟 usState
幾乎一致,學習成本幾乎能夠忽略,更多的學習成本在於 React Hooks 的掌握和理解,通過一年多,Hooks 已經逐漸在 React 社區中獲得承認,相信之後 Hooks 將是每一個 React 開發者的基本技能。bash
對於狀態管理,最核心的功能就是狀態的跨組件通訊。useState 用於管理單一組件內的狀態,useStore 則能夠跨組件管理整個應用的狀態。
下面展現瞭如何多個組件如何共享狀態:
import React from "react"; import { useStore } from "stook"; function Counter() { const [count, setCount] = useStore("Counter", 0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); } function Display() { const [count] = useStore("Counter"); return <p>{count}</p>; } function App() { return ( <div> <Counter /> <Display /> </div> ); } 複製代碼
在這個例子中,咱們能夠看到,要共享狀態,只需使用 useStore 訂閱同一個 key 便可,很是簡單。能夠說,只要你學會了 useState,也就學會了 useStore,只要你學會了 useStore,你就學會了 React 的狀態管理。
爲了能使組件和狀態管理邏輯分離,強烈建議使用自定義 hooks 管理狀態,好比說你要管理 Counter 的狀態,那就是自定義一個叫 useCounter
的 hooks,而後在各組件中使用 useCounter()
, 而不是直接使用 useStore('Counter')
。
示例:
import React from "react"; import { useStore } from "stook"; function useCounter() { const [count, setCount] = useStore("Counter", 0); const decrease = () => setCount(count - 1); const increase = () => setCount(count + 1); return { count, increase, decrease }; } function Display() { const { count } = useCounter(); return <div>{count}</div>; } function Increase() { const { increase } = useCounter(); return <buttun onClick={increase}>+</buttun>; } function Decrease() { const { decrease } = useCounter(); return <buttun onClick={decrease}>-</buttun>; } export default function App() { return ( <div> <Decrease /> <Display /> <Increase /> </div> ); } 複製代碼
上面三個子組件,都用到了 useCounter,它們實現了狀態共享。
自定義 Hooks 是最佳實踐,強烈建議在業務中都使用自定義 Hooks。
Stook 的核心很是簡潔,核心 Api 就 useStore
一個,所有 Api 也就 3 個:
測試 stook 是一件很是簡單的事,由於測試 stook 也就是在測試 react hooks。
推薦使用 react-hooks-testing-library工具來測試 stook。
npm install -D @testing-library/react-hooks react-test-renderer
複製代碼
useCounter.ts
function useCounter() { const [count, setCount] = useStore("Counter", 0); const decrease = () => setCount(count - 1); const increase = () => setCount(count + 1); return { count, increase, decrease }; } 複製代碼
useCounter.test.ts
import { renderHook, act } from "@testing-library/react-hooks"; import useCounter from "./useCounter"; test("should increment counter", () => { const { result } = renderHook(() => useCounter()); act(() => { result.current.increase(); }); expect(result.current.count).toBe(1); }); 複製代碼
更多的測試技巧請看:react-hooks-testing-library。
爲了更好的編程體驗,Stook 支持使用 Redux DevTools 調試。
若是你未安裝 Redux DevTools extension,請安裝相應瀏覽器的插件:Redux DevTools。
使用 devtools 很是簡單,先安裝 stook-devtools
包:
npm i stook-devtools
複製代碼
而後在項目代碼中進入,並初始化:
import { devtools } from "devtools"; devtools.init(); 複製代碼
若是你不想在生產環境引入:
import { devtools } from "devtools"; if (process.env.NODE_ENV !== "production") { devtools.init(); } 複製代碼
生效後,能夠在瀏覽器的 Redux DevTools extension 看到整個應用的 state 狀態:
Stook 的理念和傳統的狀態管理方案不一樣,沒有明確的 Action 的概念。事實上,它的理念跟 React 的 useState
是相似的,推崇的是:一個 Hooks,一個 state,一個 action。Stook 建議把狀態分拆,變成一個個 Hooks,而後就變成 [state, setState]
。
更多關於 Stook 的用法,請看 Github: Stook。