😉

Zustandの紹介

2024/01/06に公開

状態管理とZustandの紹介

状態管理とは

Web開発における「状態管理」とは、アプリケーションの状態(データやUIの状態)を管理し、アプリケーション全体で一貫性を保つためのプロセスです。例えば、ユーザーのログイン情報、ページに表示されるデータ、ユーザーの操作に応じて変化するUIの状態などがこれに含まれます。適切な状態管理は、アプリケーションの予測可能性、メンテナンスの容易さ、および全体的なパフォーマンスに大きく影響します。

なぜ状態管理が重要なのか?

大規模なアプリケーションでは、多数のコンポーネント間で状態を共有し、同期させる必要があります。状態が不整合になると、バグの原因になり、ユーザーエクスペリエンスを損なう可能性があります。したがって、効率的で一貫性のある状態管理は、アプリケーションの信頼性を高めるのに不可欠です。

Zustand

公式: https://zustand-demo.pmnd.rs/

Zustandは、Reactのための軽量な状態管理ライブラリです。Zustandはドイツ語で「状態」を意味し、その名の通り、Reactアプリケーション内で状態を簡単に管理するために設計されています。このライブラリは、状態をグローバルに保持し、どのコンポーネントからもアクセスできるようにすることで、状態の共有と同期を容易にします。また、Zustandは、フックベースの快適なAPIを備えた、小さくて高速なスケーラブルな状態管理ソリューションです。

ZUSTANDの基礎

Zustandのインストールとセットアップ

Zustandを使用するには、まずライブラリをプロジェクトにインストールする必要があります。

その前に下記のようなシンプルな構成で考えていきます。storeには状態を管理するファイル、componentsにはその状態を表示するファイルを管理しています。

my-zustand-app/
├── src/
│   ├── store/
│   │   ├── index.ts
│   │   └── userStore.ts
│   ├── components/
│   │   ├── UserProfile.tsx
│   └── App.tsx
├── package.json
└── tsconfig.json

まず、store配下のuserStoreを使っていきます。userStoreはユーザー情報を管理し、状態の読み取りや更新を行うZustandのストアです。

import create from 'zustand'

type UserState = {
  username: string;
  setUsername: (name: string) => void;
}

export const useUserStore = create<UserState>(set => ({
  username: 'Guest',
  setUsername: (name) => set({ username: name }),
}));

ストアの説明をすると下記になります。

  1. 型定義 (UserState): UserState 型を定義しています。これは username という文字列と、setUsername という関数が含まれています。setUsername 関数は引数として文字列を受け取ります。
  2. 初期状態の設定: ストアの初期状態として、username が ‘Guest’ に設定されています。これは、ストアが作成されたときのユーザー名のデフォルト値です。
  3. 状態更新関数 (setUsername): setUsername 関数を通じて、外部から状態(この場合は username)を更新できます。この関数は set コールバックを使用して、新しい username の値で状態を更新します。
  4. ストアの作成とエクスポート: create 関数を使用してストアを作成し、useUserStore としてエクスポートしています。これにより、アプリケーションの他の部分からこのストアにアクセスし、ユーザー名を読み取ったり更新したりできます。

このストアをコンポーネント側で利用します。

import React from 'react'
import { useUserStore } from '../store/userStore'

export const UserProfile: React.FC = () => {
  const { username, setUsername } = useUserStore();

  return (
    <div>
      <h1>User Profile</h1>
      <p>Username: {username}</p>
      <button onClick={() => setUsername('NewUsername')}>Change Username</button>
    </div>
  )
}

useUserStoreをimportして先程のstate、およびstateの更新関数を呼び出します。かんたんですが、こんな感じで状態管理を行い、その状態を表示&更新します。

他ライブラリ(Redux)との比較

Zustandと他の状態管理ライブラリ(例えばReduxやContext API)とのパフォーマンス比較に関しては、以下のポイントで考慮していきます。

  1. 軽量性: Zustandは非常に軽量なライブラリであり、追加の依存関係が少ないため、アプリケーションのバンドルサイズにほとんど影響を与えません。

  2. 最適化されたレンダリング: ZustandはReactのHooksを利用しており、コンポーネントが必要とする状態の部分のみを購読することができます。これにより、不要なレンダリングを避け、パフォーマンスを向上させることが可能です。対照的に、Reduxなどの他のライブラリでは、より細かいレンダリングの最適化が必要な場合があります。

  3. シンプルな設計: Zustandは、使いやすさとシンプルさに重点を置いて設計されています。これにより、状態管理のための追加的なボイラープレートや複雑さが減少し、結果としてパフォーマンスに好影響を与えることがあります。

  4. カスタマイズ性: Zustandはカスタマイズ可能なミドルウェアをサポートしており、パフォーマンスの最適化や特定のユースケースに合わせた調整が可能です。

以上の点を踏まえ、Zustandはその軽量性と最適化されたレンダリング戦略により、特に小規模から中規模のプロジェクトで優れたパフォーマンスを提供する可能性があります。

「対照的に、Reduxなどの他のライブラリでは、より細かいレンダリングの最適化が必要な場合」というのは具体的に説明します。Reduxのような状態管理ライブラリでは、不要なコンポーネントの再レンダリングを防ぐために追加の労力が必要になるということです。

Reduxの場合

  1. グローバルな状態: Reduxでは、アプリケーションの状態は一つの大きな「ストア」に格納されます。このストアはアプリケーションのどの部分からもアクセスできるグローバルな状態です。

  2. コンポーネントの購読: コンポーネントは、必要な状態の部分をこのストアから購読します。しかし、Reduxの初期の設計では、ストアのどの部分が更新されても、その状態を購読するすべてのコンポーネントが再レンダリングされる可能性があります。

  3. 最適化の必要性: その結果、アプリケーションのパフォーマンスを保持するためには、開発者が手動で最適化を行う必要があります。

Zustandの場合

一方で、Zustandは異なるアプローチを取ります。

  1. フックベースの購読: ZustandはReactのフックを使用して、コンポーネントがストアの特定の部分のみを購読することを可能にします。

  2. 最適化されたレンダリング: これにより、コンポーネントはストアの関連する部分が変更された時のみ再レンダリングされます。結果として、開発者は手動での最適化にかかる労力を大幅に削減できます。

つまり、Reduxを使用する場合、アプリケーションのパフォーマンスを維持するためには、状態が変更された際に不必要な再レンダリングが起きないように注意深い設計や追加のライブラリが必要です。

対照的に、Zustandはこの種の最適化をよりシンプルにするアプローチを提供します。

まとめ

基礎の基礎として、zustandを紹介しました。発端は下記の記事を見て、「zustandって何?」となったことから書き起こして見ました。

https://zenn.dev/kazukix/articles/react-setup-2024

次回はzustandのカスタマイズ性を踏まえて、実用的な部分を深堀りしていきたいと思います!

Discussion