この章では、Next.jsアプリケーションにおける状態管理について学びます。状態管理とは、アプリケーション全体で共有されるデータを効率的に管理し、コンポーネント間でデータの受け渡しをスムーズに行うための仕組みです。ここでは、Reactの標準機能であるContext APIと、より高機能な状態管理ライブラリであるZustandの特徴、基本的な使い方、そしてNext.jsアプリケーションへの導入方法を解説します。
1. 状態管理の必要性
小規模なアプリケーションでは、propsのバケツリレー(props drilling)でも状態を管理できるかもしれません。しかし、アプリケーションが大きくなるにつれて、コンポーネントの階層が深くなり、propsだけで状態を管理するのが難しくなります。
状態管理ライブラリを使用すると、アプリケーション全体で共有される状態を一元管理し、どのコンポーネントからでも簡単にアクセスできるようになります。これにより、コードの可読性と保守性が向上し、開発効率がアップします。
2. Context API
Context APIは、Reactに組み込まれている状態管理の仕組みです。特別なライブラリをインストールする必要がなく、手軽に導入できるのが特徴です。
Contextの作成
まずは、状態を保持するためのContextを作成します。createContext
関数を使って、新しいContextを作成します。
tsx
// contexts/ThemeContext.tsx
import { createContext, Dispatch, SetStateAction } from 'react';
type Theme = 'light' | 'dark';
type ThemeContextType = {
theme: Theme;
setTheme: Dispatch<SetStateAction<Theme>>;
};
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
export default ThemeContext;
この例では、テーマ(light
またはdark
)を管理するためのThemeContext
を作成しています。ThemeContextType
で、Contextが保持するデータの型を定義しています。
Providerの設定
作成したContextをアプリケーション全体で使えるようにするには、Provider
コンポーネントを使って、Contextを適用したいコンポーネントツリーを囲みます。
tsx
// pages/_app.tsx
import { useState } from 'react';
import ThemeContext from '../contexts/ThemeContext';
import type { AppProps } from 'next/app';
function MyApp({ Component, pageProps }: AppProps) {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Component {...pageProps} />
</ThemeContext.Provider>
);
}
export default MyApp;
_app.tsx
で、ThemeContext.Provider
を使ってアプリケーション全体を囲んでいます。value
属性に、Contextで共有したいデータを指定します。
Contextの使用
Contextにアクセスするには、useContext
フックを使用します。
tsx
// components/ThemeSwitcher.tsx
import { useContext } from 'react';
import ThemeContext from '../contexts/ThemeContext';
const ThemeSwitcher = () => {
const themeContext = useContext(ThemeContext);
if (!themeContext) {
return null;
}
const { theme, setTheme } = themeContext;
const toggleTheme = () => {
setTheme(theme === 'light' ? 'dark' : 'light');
};
return (
<button onClick={toggleTheme}>
Switch to {theme === 'light' ? 'dark' : 'light'} mode
</button>
);
};
export default ThemeSwitcher;
useContext
フックにThemeContext
を渡すことで、ThemeContext
の値を取得できます。この例では、ボタンをクリックするとテーマが切り替わるコンポーネントを作成しています。
3. Zustand
Zustandは、シンプルで使いやすい状態管理ライブラリです。Context APIよりも高機能で、大規模なアプリケーションの状態管理に適しています。
Zustandのインストール
まず、Zustandをインストールします。
bash
npm install zustand
# または
yarn add zustand
# または
pnpm add zustand
ストアの作成
Zustandでは、状態を管理するためのストアを作成します。create
関数を使って、新しいストアを作成します。
tsx
// stores/useCounterStore.ts
import { create } from 'zustand';
type CounterState = {
count: number;
increment: () => void;
decrement: () => void;
};
const useCounterStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
export default useCounterStore;
この例では、カウンターの状態を管理するためのuseCounterStore
を作成しています。count
という状態と、increment
、decrement
という状態を更新するための関数を定義しています。
ストアの使用
ストアにアクセスするには、useCounterStore
フックを使用します。
tsx
// components/Counter.tsx
import useCounterStore from '../stores/useCounterStore';
const Counter = () => {
const { count, increment, decrement } = useCounterStore();
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
};
export default Counter;
useCounterStore
フックを呼び出すだけで、ストアの状態と更新関数を取得できます。この例では、カウントを表示し、+
ボタンと-
ボタンでカウントを増減できるコンポーネントを作成しています。
4. Context APIとZustandの比較
特徴 | Context API | Zustand |
---|---|---|
導入のしやすさ | 組み込み機能なので、インストール不要 | ライブラリのインストールが必要 |
学習コスト | 低い | やや高い(ただし、使い方はシンプル) |
機能 | 必要最低限の機能を提供 | 高機能(ミドルウェア、開発ツールなど) |
パフォーマンス | 大規模なアプリケーションでは、再レンダリングに注意が必要 | 状態の変更に関連するコンポーネントのみを再レンダリング |
適用範囲 | 小規模〜中規模アプリケーション | 中規模〜大規模アプリケーション |
Context APIは、Reactに組み込まれているため、手軽に導入できるのがメリットです。しかし、大規模なアプリケーションでは、パフォーマンスの問題が発生する可能性があります。
Zustandは、シンプルで使いやすいAPIを提供し、パフォーマンスにも優れています。また、ミドルウェアや開発ツールなどの機能も充実しています。
5. その他の状態管理ライブラリ
Context APIとZustand以外にも、状態管理ライブラリはいくつか存在します。
- Redux: 最も有名な状態管理ライブラリの一つ。大規模アプリケーションでよく使用されるが、学習コストが高く、ボイラープレートが多いというデメリットがある。
- Recoil: Facebookが開発した状態管理ライブラリ。Reactとの親和性が高く、パフォーマンスにも優れている。
- Jotai: プリミティブなアプローチで状態を管理するライブラリ。シンプルで使いやすく、パフォーマンスにも優れている。
どの状態管理ライブラリを選ぶかは、アプリケーションの規模や要件、開発チームの好みなどによります。