【初心者向け】ReactのuseStateフックとContext APIでコンポーネント間ステート共有をマスターしよう
ReactにおけるuseStateフックとコンポーネント間ステート共有
コンポーネント間ステート共有には、主に以下の3つの方法があります。
それぞれの方法には一長一短があり、状況に応じて最適な方法を選択する必要があります。
useStateフックとContext APIを組み合わせることで、柔軟かつ効率的なステート共有を実現することもできます。
以下、それぞれの方法の例と、useStateフックとの使い分けについて詳しく説明します。
props渡し
例:
// 親コンポーネント
const Parent = () => {
const [count, setCount] = useState(0);
return (
<div>
<Child count={count} setCount={setCount} />
</div>
);
};
// 子コンポーネント
const Child = ({ count, setCount }) => {
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => setCount(count + 1)}>インクリメント</button>
</div>
);
};
説明:
- 親コンポーネント
Parent
は、count
というステートと、そのステートを更新するための関数setCount
を持っています。 - 親コンポーネントは、
Child
コンポーネントにcount
とsetCount
をpropsとして渡します。 Child
コンポーネントは、受け取ったcount
を表示し、setCount
を使ってボタンクリック時にcount
をインクリメントします。
useStateフックとの使い分け:
- シンプルで理解しやすい
- コンポーネント階層が浅い場合に適している
- ステートの更新処理が単純な場合に適している
注意点:
- コンポーネント階層が深くなると、props渡しによるコードが冗長になり、メンテナンスが難しくなる
- 双方向データバインディングのように見えるが、実際は一方通行であることに注意が必要
Context API
// ステートコンテキストを作成
const CountContext = React.createContext({ count: 0, setCount: () => {} });
// 親コンポーネント
const Parent = () => {
const [count, setCount] = useState(0);
return (
<CountContext.Provider value={{ count, setCount }}>
<Child />
</CountContext.Provider>
);
};
// 子コンポーネント
const Child = () => {
const { count, setCount } = React.useContext(CountContext);
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => setCount(count + 1)}>インクリメント</button>
</div>
);
};
CountContext
というステートコンテキストを作成します。- 親コンポーネントは、
CountContext.Provider
を使ってステートコンテキストの値 (count
とsetCount
) を子コンポーネントに提供します。 Child
コンポーネントは、React.useContext
フックを使ってステートコンテキストの値を取得します。
- コードがスッキリし、ステート更新処理も容易
- 複数階層のコンポーネント間でステートを共有する場合に適している
- グローバルスコープに近い性質を持つため、誤った使い方
テーマコンテキストの作成
import React from 'react';
const ThemeContext = React.createContext({
theme: 'light',
setTheme: () => {},
});
export default ThemeContext;
親コンポーネント
import React, { useState } from 'react';
import ThemeContext from './ThemeContext';
const Parent = () => {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<div>
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
テーマ切替
</button>
<Child />
</div>
</ThemeContext.Provider>
);
};
export default Parent;
import React, { useContext } from 'react';
import ThemeContext from './ThemeContext';
const Child = () => {
const { theme } = useContext(ThemeContext);
const style = {
backgroundColor: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#000' : '#fff',
};
return (
<div style={style}>
<p>テーマ: {theme}</p>
</div>
);
};
export default Child;
ThemeContext
というテーマコンテキストを作成します。このコンテキストには、theme
とsetTheme
というプロパティがあります。theme
プロパティは、現在のテーマを表す文字列です。setTheme
プロパティは、テーマを切り替えるための関数です。- 親コンポーネント
Parent
は、useState
フックを使ってtheme
ステートを管理します。 - 子コンポーネント
Child
は、useContext
フックを使ってThemeContext
からtheme
プロパティを取得します。 Child
コンポーネントは、theme
プロパティに基づいてコンポーネントのスタイルを設定します。
この例では、useState フックを使ってテーマステートを管理し、Context API を使ってそのステートを子コンポーネントに共有しています。
このサンプルコードはあくまでも基本的な例であり、実際のアプリケーションでは状況に応じて様々な拡張を行うことができます。
Reactにおけるコンポーネント間ステート共有:その他の方法
Redux Saga:
- 大規模なアプリケーションにおける非同期処理を含む複雑なステート管理に適したライブラリです。
- Reduxと組み合わせることで、非同期処理の副作用をカプセル化し、アプリケーションのコードをより予測可能でテストしやすくすることができます。
- しかし、学習曲線が比較的高く、導入コストも大きくなります。
MobX:
- 状態管理を容易にするためにオブザーバブルベースのアプローチを採用したライブラリです。
- ストア内のステートが変更されると、自動的にビューを更新します。
- Reduxよりもシンプルで軽量ですが、複雑なアプリケーションには向かない場合があります。
Zustand:
- シンプルで使いやすい状態管理ライブラリです。
- ReduxやMobXよりも軽量で、学習曲線も緩やかです。
- 小規模から中規模のアプリケーションに適しています。
Recoil:
- React Context APIとReduxの機能を組み合わせたようなライブラリです。
- 宣言型であり、使いやすいインターフェースを提供しています。
- まだ比較的新しいライブラリですが、注目を集めています。
カスタムフック:
- 独自のステート管理ロジックをカプセル化するために、カスタムフックを作成することができます。
- Context APIやReduxと組み合わせて使用することができます。
- 柔軟性がありますが、コードが増えて複雑になる可能性があります。
最適な方法の選択
コンポーネント間ステート共有に最適な方法は、アプリケーションの規模、複雑性、要件によって異なります。
- シンプルなアプリケーションであれば、props渡しで十分な場合があります。
- 複数階層のコンポーネント間でステートを共有する必要がある場合は、Context APIが適しています。
- 大規模なアプリケーションで複雑なステート管理が必要な場合は、ReduxやMobXなどのライブラリを検討する必要があります。
それぞれの方法のメリットとデメリットを理解し、状況に応じて適切な方法を選択することが重要です。
ご参考になりましたでしょうか?
javascript reactjs react-hooks