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

從 Hooks 提及

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

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

回顧 Stamen

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

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

因此我建立了 Stamen,Stamen 相比 Redux 更加簡潔,對 TypeScript 支持度更好。一年多過去了,也在幾個小項目中實踐過,發現並無很好知足個人兩個指望。web

Stamen 的 Api 借鑑了 dva 和 rematch,致使了它沒有脫離 Redux 的影子,依然有 state、reducers、effects、dispatch、selector 等概念,能夠說沒有完全 Hooks 化,特別是 reducers 處理同步和 effects 處理反作用讓我以爲特別扭。chrome

一年後,我建立了更加完全 Hooks 化的狀態管理庫:Stooknpm

關於 Stook

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>
  );
}
複製代碼

Edit ancient-night-gyres

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>
  );
}
複製代碼

Edit vibrant-swirles-jw7kw

在這個例子中,咱們能夠看到,要共享狀態,只需使用 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>
  );
}
複製代碼

Edit nameless-shadow-ozke5

上面三個子組件,都用到了 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 狀態:

devtools

總結

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

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

相關文章
相關標籤/搜索