Zustand入門！Reactの状態管理をシンプルに！？

Reactが使われている案件の機能追加に携わっている。

Reactだけでもお作法があるのにファイルの上側にはimport zustandの文字が。。。
何やらReactの状態管理を綺麗にできるとのこと。

グローバルな状態管理もできちゃうらしい。
なんだグローバルって。。。。。。。
ということでいつも通り自分の勉強用に調べる。

# Zustandとは

Reactを使用していると、アプリケーション内で複数のコンポーネント間で状態を共有する必要が出てくる。  
そこで登場するのが、軽量な状態管理ライブラリ**Zustand**！！！


---

## 基本用語の解説

### 状態って・・・・何

**状態**（State）はアプリケーションやコンポーネントが持つ情報やデータのこと。  
例：カウンターの数値、ユーザーのログイン情報、入力フォームの値など。

### グローバルな状態管理って・・・・何

**グローバルな状態管理**はアプリ全体で共有・利用される状態を一元管理する仕組み。  
通常のReactでは、各コンポーネントが独自の状態（ローカル状態）を持っている。  
複数のファイル間やコンポーネント間で同じ状態を扱う必要がある場合は共有や受け渡しが煩雑になりやすい。  
そこでZustandを使うと、簡単にグローバルな状態管理が行えるというわけ。

### コンポーネントって・・・・何

**コンポーネント**は、Reactで作成するUI部品のこと。  
基本的には関数やクラスとして定義される。
画面上に表示する部品（例：ボタン、フォーム、カウンターなど）を表現する。

各コンポーネントは独自の状態を持つことができる。
複数のコンポーネント間で共通の情報を扱う場合はグローバルな状態管理が有効になる。

### フックって・・・・何

**フック**（Hook）はReactの関数コンポーネント内で状態管理や副作用処理を行うための仕組み。  
`useState`や`useEffect`がある。

Zustandも独自のフック（例：`useCounterStore`）を提供している。
これを使うと他のファイルから状態管理の機能をimportして簡単に利用することができる。

---

## Zustandの基本的な使い方

### 1. Zustandのインストール

```
npm install zustand
```

### 2. ストア（状態の倉庫）を作成する

Zustandは`create()` 関数を使って状態管理用のストアを定義。  
ストアには、**状態そのもの** と **その状態を更新するアクション（関数）** をまとめている。

```tsx
import { create } from 'zustand';

type State = {
  count: number;
  increase: () => void;
  reset: () => void;
};

export const useCounterStore = create<State>((set) => ({
  count: 0,
  increase: () => set((state) => ({ count: state.count + 1 })),
  reset: () => set({ count: 0 }),
}));
```

### 3. コンポーネントでストアを利用する

作成したストアを利用するために、コンポーネント内でZustandのフック（`useCounterStore`）を呼ぶ。  

グローバルに管理された状態を簡単に取得・更新できる。

```tsx
// Counter.tsx
import { useCounterStore } from './store';

const Counter = () => {
  const count = useCounterStore((state) => state.count);
  const increase = useCounterStore((state) => state.increase);
  const reset = useCounterStore((state) => state.reset);

  return (
    <div>
      <p>現在のカウント: {count}</p>
      <button onClick={increase}>+1</button>
      <button onClick={reset}>リセット</button>
    </div>
  );
};

export default Counter;
```

---

## よく使われるメソッドと概念

| メソッド・概念         | 説明                                                                                |
|------------------------|-------------------------------------------------------------------------------------|
| `create()`           | Zustandのストア（状態管理の倉庫）を作成するための関数                                  |
| `set()`              | ストア内の状態を更新するための関数                                                     |
| `get()`              | 現在の状態を取得するための関数                                 |
| `subscribe()`        | 状態の変化を監視するためのメソッド                                      |
| `persist` ミドルウェア | 状態をlocalStorageなどに保存するための仕組み  |

---

## ReactとZustandの役割分担

| 利用シーン                                  | Zustand（グローバル状態管理） | React（`useState`などのローカル状態） |
|---------------------------------------------|-------------------------------|-----------------------------------------|
| 複数コンポーネント間で共有する状態の管理       |◯                        |✗                                     |
| 一時的なローカル状態管理                     | ✗                       | ◯                                      |
| フォーム入力等の単一コンポーネントの状態管理   | ✗                           |◯                                     |
| ログイン情報、検索条件など共通の情報の管理     |◯                            | ✗                                     |

---

## ミドルウェア

Zustandはミドルウェアを利用して状態の永続化などを簡単に行うことができるらしい。  
例えば`persist`ミドルウェアを利用して、ユーザー名をlocalStorageに保存できる。

```tsx
// userStore.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

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

export const useUserStore = create<UserState>(
  persist(
    (set) => ({
      name: '',
      setName: (name: string) => set({ name }),
    }),
    {
      name: 'user-storage', // localStorageに保存されるキー名
    }
  )
);
```

---

## Reactで昔ながらの状態共有方法はProps

**Propsの受け渡し（親 → 子）**
`return`で渡すファイルを直接指定。


親(parent.tsx)
```tsx
const Parent = () => {
  const [count, setCount] = useState(0);

  return <Child count={count} setCount={setCount} />;
};
```
子（Chile.tsx）
```tsx
const Child = ({ count, setCount }) => (
  <div>
    <p>{count}</p>
    <button onClick={() => setCount(count + 1)}>+1</button>
  </div>
);
```

## 一言
概要は分かった。後は使うだけ！