Stook:極簡主義的React狀態管理庫

NO IMAGE

從 Hooks 說起

一年前,2018 年 9 月左右, React hooks 剛發佈,那時 hooks 還不是穩定 Api,只能在 16.7.0-alpha.0 版本能用。那時我就預感到,基於 hooks 狀態管理解決方案會逐漸崛起,當時我基於 hooks 創建一個我認為理想的狀態管理庫:stamen

我還寫過一篇文章介紹它:可能是基於 Hooks 和 Typescript 最好的狀態管理工具

回顧 Stamen

我之前說過,我想要這樣的一個狀態管理庫:

  • 簡單易用,並且適合中大型項目
  • 完美地支持 Typescript

所以我創建了 Stamen,Stamen 相比 Redux 更加簡潔,對 TypeScript 支持度更好。一年多過去了,也在幾個小項目中實踐過,發現並沒有很好滿足我的兩個期望。

Stamen 的 Api 借鑑了 dva 和 rematch,導致了它沒有脫離 Redux 的影子,依然有 state、reducers、effects、dispatch、selector 等概念,可以說沒有徹底 Hooks 化,特別是 reducers 處理同步和 effects 處理副作用讓我覺得特別扭。

一年後,我創建了更加徹底 Hooks 化的狀態管理庫:Stook

關於 Stook

Stook,中文翻譯是谷堆,命名靈感來自 store、hooks 兩個單詞的組合,一個極簡主義的 React 狀態管理庫。

基本用法

我們看看 Stook 用法有多麼的簡單,下面是一個經典的 Counter 組件,展示了 stook 的最基本用法:

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:極簡主義的React狀態管理庫

Stook 最核心的 Api 就是 useStore,也許你發現了,它和 useState 非常像,實際上,useStore 除了多了一個參數以外,其他用法一模一樣。

Stook 極簡之處在於它的用法跟 usState 幾乎一致,學習成本幾乎可以忽略,更多的學習成本在於 React Hooks 的掌握和理解,經過一年多,Hooks 已經逐漸在 React 社區中得到認可,相信以後 Hooks 將是每個 React 開發者的基本技能。

狀態共享

對於狀態管理,最核心的功能就是狀態的跨組件通信。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>
);
}

Stook:極簡主義的React狀態管理庫

在這個例子中,我們可以看到,要共享狀態,只需使用 useStore 訂閱同一個 key 即可,非常簡單。可以說,只要你學會了 useState,也就學會了 useStore,只要你學會了 useStore,你就學會了 React 的狀態管理。

自定義 Hooks

為了能使組件和狀態管理邏輯分離,強烈建議使用自定義 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>
);
}

Stook:極簡主義的React狀態管理庫

上面三個子組件,都用到了 useCounter,它們實現了狀態共享。

自定義 Hooks 是最佳實踐,強烈建議在業務中都使用自定義 Hooks。

Api

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 extension,請安裝相應瀏覽器的插件:Redux DevTools

Setup

使用 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:極簡主義的React狀態管理庫

總結

Stook 的理念和傳統的狀態管理方案不同,沒有明確的 Action 的概念。事實上,它的理念跟 React 的 useState是類似的,推崇的是:一個 Hooks,一個 state,一個 action。Stook 建議把狀態分拆,變成一個個 Hooks,然後就變成 [state, setState]

更多關於 Stook 的用法,請看 Github: Stook

相關文章

一次kafka消息堆積問題排查

第三屆SEEConf2020演講資料(PPT)

Spring工程多數據源多個事務管理器導致事務失效

假如你的同事寫了這樣的代碼:a&&d||b&&c&&!d||(!a||!b)&&c