【React Hooks】useContextの使い方を解説!コンポーネント間でデータを共有する方法は?

当サイトでは一部リンクに広告が含まれています
Reactアイコン

Reactを使ってプログラミングをするとき、データをコンポーネント間で共有する方法が必要になることがあります。
そのための便利なツールがuseContextというものです。
この記事では、useContextの使い方とそのメリット、注意点についてわかりやすく解説します。

目次

React Hooksとは?

React Hooksとは、Reactのバージョン16.8から導入された新機能で、関数型コンポーネントでステートやライフサイクルといった機能を使うことができるようになりました。
useStateuseEffectなどがよく知られていますが、今回はその中の一つ、useContextについて詳しく見ていきましょう。

ReactのuseContextとは?

useContextは、Reactのコンテキスト(Context)を関数型コンポーネントで使うためのHookです。

コンテキストとは、コンポーネント間でデータを共有するための仕組みのことです。

これを使うと、親コンポーネントから子コンポーネントへとデータを渡すときに、中間のコンポーネントを経由せずに直接データを渡すことができます。

useContextのメリット

useContextの最大のメリットは、コンポーネント間でデータを簡単に共有できることです。

これにより、親コンポーネントから子コンポーネントへとデータを渡すときに、中間のコンポーネントを経由せずに直接データを渡すことができます。
これは、大規模なアプリケーションで特に有用です。

また、useContextを使うと、グローバルな状態を管理することができます。
これにより、アプリケーション全体で共有する必要があるデータ(例えば、ログインユーザーの情報やテーマの設定など)を簡単に管理することができます。

useStateとの違いは?

useStateuseContextは、どちらもReact Hooksの一部であり、関数型コンポーネントでステートを扱うためのものです。
しかし、それぞれが扱うステートの範囲が異なります。

useStateは、一つのコンポーネント内でのステートを扱います。
つまり、useStateを使って作成したステートは、そのコンポーネント内でのみアクセス可能です。

一方、useContextは、複数のコンポーネント間でステートを共有するためのものです。
つまり、useContextを使って作成したステートは、そのコンテキストを使っているすべてのコンポーネントでアクセス可能です。

useContextの使い方

まずは、useContextの基本的な使い方から見ていきましょう。

import React, { useContext } from 'react';

const MyContext = React.createContext();

function MyComponent() {
  const value = useContext(MyContext);
  return <p>受け取ったデータ: {value}</p>;
}

function App() {
  return (
    <MyContext.Provider value="こんにちは、世界!">
      <MyComponent />
    </MyContext.Provider>
  );
}

export default App;

このコードでは、まずReact.createContext()を使って新しいコンテキストを作成しています。
そして、MyContext.Providerコンポーネントを使って、そのコンテキストに値を設定します。
この値は、value属性を使って設定します。

そして、useContext(MyContext)を使って、そのコンテキストの値を取得します。
この値は、MyContext.Providerで設定した値となります。

【具体例】useContextを使ったテーマ切り替えの実装

ここでは、useContextを使ってテーマ(ライトモードとダークモード)を切り替える機能を実装する例を見てみましょう。

import React, { useContext, useState } from 'react';

const ThemeContext = React.createContext();

function MyComponent() {
  const { theme, toggleTheme } = useContext(ThemeContext);
  return (
    <div style={{ backgroundColor: theme === 'dark' ? 'black' : 'white', color: theme === 'dark' ? 'white' : 'black' }}>
      <p>現在のテーマ: {theme}</p>
      <button onClick={toggleTheme}>テーマ切り替え</button>
    </div>
  );
}

function App() {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      <MyComponent />
    </ThemeContext.Provider>
  );
}

export default App;

このコードでは、ThemeContextというコンテキストを作成し、その中にthemetoggleThemeという2つの値を持たせています。
そして、MyComponentコンポーネントでは、そのコンテキストの値を取得し、それを使ってテーマを切り替える機能を実装しています。

useContextで複数の値を扱う

useContextは、一つの値だけでなく、複数の値を扱うこともできます。
そのためには、コンテキストの値をオブジェクトにすることで、そのオブジェクトの中に複数の値を持たせることができます。

import React, { useContext } from 'react';

const MyContext = React.createContext();

function MyComponent() {
  const { message, author } = useContext(MyContext);
  return (
    <div>
      <p>メッセージ: {message}</p>
      <p>作者: {author}</p>
    </div>
  );
}

function App() {
  return (
    <MyContext.Provider value={{ message: 'こんにちは、世界!', author: '太郎' }}>
      <MyComponent />
    </MyContext.Provider>
  );
}

export default App;

このコードでは、MyContext.Providervalue属性にオブジェクトを設定しています。
そして、useContext(MyContext)を使ってそのオブジェクトを取得し、その中のmessageauthorの値を取り出しています。

useContextの注意点

useContextを使う場所

useContextは、関数コンポーネントのトップレベルで呼び出す必要があります。
つまり、ループや条件分岐、ネストした関数の中でuseContextを呼び出すことはできません。

例えば、以下のようなコードはエラーになります。

function MyComponent() {
  const value = 0;
  if (value === 0) {
    const contextValue = useContext(MyContext);  // これはエラーになります
  }
  // ...
}

このコードでは、if文の中でuseContextを呼び出そうとしていますが、これはReactのルールに違反しているためエラーになります。

useContextのパフォーマンスについて

useContextを使うとき、パフォーマンスに影響を及ぼす可能性があります。
なぜなら、コンテキストの値が変更されると、そのコンテキストを使っているすべてのコンポーネント

が再レンダリングされるからです。

例えば、以下のようなコードを考えてみましょう。

import React, { useContext, useState } from 'react';

const MyContext = React.createContext();

function MyComponent() {
  const { message } = useContext(MyContext);
  return <p>メッセージ: {message}</p>;
}

function App() {
  const [count, setCount] = useState(0);

  return (
    <MyContext.Provider value={{ message: 'こんにちは、世界!', count }}>
      <MyComponent />
      <button onClick={() => setCount(count + 1)}>カウントアップ</button>
    </div>
  );
}

export default App;

このコードでは、MyComponentコンポーネントはMyContextmessageの値を使っています。
しかし、MyContext.Providervalueにはcountの値も含まれています。
そのため、countの値が変更されると、MyComponentコンポーネントも再レンダリングされます。

これは、MyComponentコンポーネントがcountの値を使っていないにも関わらず、再レンダリングが発生するため、パフォーマンスに影響を及ぼす可能性があります。

この問題を解決するためには、異なる値を扱うための別々のコンテキストを作成すると良いでしょう。

React を効率的に身につける勉強法は?

React には興味があっても、プログラミング学習をはじめたばかりであれば、以下のような疑問を持つかもしれません。

  • Reactエンジニアとして活躍するために何をすればいい?
  • 何から勉強すればいいんだろう?
  • 絶対に転職を成功させるには?

React は習得が比較的難しいため、勉強法の選び方を間違うと時間・労力・お金が無駄になってしまいます…。

そのため、こちらの記事を参考に、ご自身に最適な学習方法を選んでみませんか?

目次