
React状態管理ライブラリ Zustandのミドルウェアを使ってみた
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは。データアナリティクス事業本部 サービスソリューション部の北川です。
Zustandとは
ZustandはReactの状態管理ライブラリの一つです。シンプルで使いやすく、他の状態管理ライブラリと比べてもコード量が少ないです。
基本的な使い方については、以下のエントリで書いています。
今回は、Zustandのミドルウェアを使ってみました。基本的には、公式のGitHubに沿って進めています。
Next.jsプロジェクトを作成
前回、エントリで使用したコードをそのまま使っていきます。
$ npx create-next-app sample-zustand --ts
$ yarn add zustand // または $ npm install zustand
import create from "zustand";
type Count = {
  count: number;
  increaseCount: () => void;
  resetCount: () => void;
}
export const useStore = create<Count>((set) => ({
  count: 0,
  increaseCount: () =>
    set((state) => {
      return { count: state.count + 1 };
    }),
  resetCount: () => set({ count: 0 }),
}));
import type { NextPage } from "next";
import { useStore } from "../libs/store";
import styles from "../styles/Home.module.css";
const Count = () => {
  const count = useStore((state) => state.count);
  console.log(count);
  return (
    <>
      <h2>count: {count}</h2>
    </>
  );
};
const IncreaseCountButton = () => {
  const increaseCount = useStore((state) => state.increaseCount);
  return <button onClick={() => increaseCount()}>Increase</button>;
};
const ResetButton = () => {
  const { resetCount } = useStore();
  return <button onClick={() => resetCount()}>Reset</button>;
};
const Home: NextPage = () => {
  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <Count />
        <IncreaseCountButton />
        <ResetButton />
      </main>
    </div>
  );
};
export default Home;

ミドルウェアを試してみる
Zustandが用意しているいくつかのミドルウェアは、"zustand/middleware"からインポートすることで使用できます。
devTools
devToolsミドルウェアを使用すると、拡張機能のRedux DevToolsを使えるようになります。 Redux DevToolsに関しては、こちらのエントリで書いています。
setの第3引数に、それぞれのactionTypeを渡すことができます。

import create from "zustand";
import { devtools } from "zustand/middleware";
type Count = {
  count: number;
  increaseCount: () => void;
  resetCount: () => void;
};
export const useStore = create<Count>()(
  devtools((set) => ({
    count: 0,
    increaseCount: () =>
      set(
        (state: { count: number }) => {
          return { count: state.count + 1 };
        },
        false,
        "increaseCount"
      ),
    resetCount: () => set({ count: 0 }, false, "resetCount"),
  }))
);

immer
immerはオブジェクトをイミュータブルに扱うためのライブラリになります。
developersIOでも、以下のエントリが投稿されています。
immerミドルウェアを使用すると、push()やunshift()などの破壊的なメソッドを使用したstateの変更ができるようになります。このミドルウェアは、"zustand/middleware/immer"からインストールします。
こちらは、公式のimmerミドルウェアを使ったコードです。
import create from 'zustand'
import { immer } from 'zustand/middleware/immer'
const useBeeStore = create(
  immer((set) => ({
    bees: 0,
    addBees: (by) =>
      set((state) => {
        state.bees += by
      }),
  }))
)
自作ミドルウェア
提供されているミドルウェアではなく、自作のミドルウェアも作成できます。Zustandのデモでは、stateの変更を記録し、ログとして出力するミドルウェアを定義しています。
import create from "zustand";
type Count = {
  count: number;
  increaseCount: () => void;
  resetCount: () => void;
};
const log = (config) => (set, get, api) =>
  config(
    (...args) => {
      console.log("  applying", args);
      set(...args);
      console.log("  new state", get());
    },
    get,
    api
  );
export const useStore = create<Count>()(
  log((set) => ({
    count: 0,
    increaseCount: () =>
      set((state: { count: number }) => {
        return { count: state.count + 1 };
      }),
    resetCount: () => set({ count: 0 }),
  }))
);

複数ミドルウェアを使う
もちろん、以下のように記述することで、複数のミドルウェアを使用できます。
export const useStore = create<Count>()(
  log(
    devtools((set) => ({
      count: 0,
      increaseCount: () =>
        set(
          (state: { count: number }) => {
            return { count: state.count++ };
          },
          false,
          "increaseCount"
        ),
      resetCount: () => set({ count: 0 }, false, "resetCount"),
    }))
  )
);
まとめ
今回は、Zustandのミドルウェアを簡単にですが、試してみました。Zustaindでは他にも、再現が難しかったのですが、stateの状態を保持するPersistミドルウェアなどもあります。
ミドルウェアは学ぶことが多くまだまだ勉強中です。これからもインプット、アウトプットに力を入れていきたいと思います。
ではまた。







