🐕

React コンテキストの使い方(useContext)

2021/09/13に公開

コンテキストについて

下記の公式ドキュメントでコンテキストはこのように説明されています。

「コンテクストは各階層で手動でプロパティを下に渡すことなく、コンポーネントツリー内でデータを渡す方法を提供します。」

コンテキストを導入していない場合は、ステートが定義した親コンポーネントから子、孫コンポーネントへプロップで渡していく必要があります。
 コンテキストを導入すると、上記のようにコンポーネント間でステートを受け渡しすることなく、ステート、イベントハンドラを一元管理して、必要な場所で呼び出すようにできるようになります。

https://ja.reactjs.org/docs/context.html

なぜコンテキストを使うのか

コンテキストを使うメリットは下記の3点あります。コンテキストを使うことでUIとロジックが分離することができるのでより開発しやすいコードになります。

  • 複数コンポーネントで同じステートを簡単に操作できる
  • ステート、イベントハンドラを一元管理できる
  • 親コンポーネントから子、孫コンポーネントへプロップスを使って渡す必要がなくなる

https://ja.reactjs.org/docs/hooks-reference.html#usecontext

コンテキストの使い方

コンテキストの使い方について説明します。コンテキストは下記の手順で使うことができます。まず、コンテキストを作成し、その作成したコンテキストのプロバイダーに値を渡します。そして、useContextフックを使ってプロバイダーに渡した値を取得します。上記の流れをコードを見ながら説明します。

1.コンテキストを作成する
2.コンテキストプロバイダーに値を渡す
3.useContextフックを使ってデータを取得する

今回は下記の公式ドキュメントの例を参考にコンテキストの使い方を説明します。
表示されるのはボタンをクリックすると、値が増えるカウンターです。
ステートの使い方がわからない方はリンクの内容を参考にしてください。
https://ja.reactjs.org/docs/hooks-overview.html

1.コンテキストを作成する

CountProvider.js
import React, { createContext } from 'react';

export const CountContext = CreateContext();

CreateContextを使ってCountContextというコンテキストを作成します。

2.コンテキストプロバイダーに値を渡す

CountProvider.js
import React, { createContext, useState } from 'react';

export const CountContext = CreateContext();

const [count, setCount] = useState(0);
const addCount = () => {
  setCount(count + 1);
};

<CountContext.Provider value={{count, addCount}}>
    <App />
</CountContext.Provider>

上記のコードの下記の箇所でコンテキストプロバイダーに値を渡しています。
コンポーネントをプロバイダーで挟むことで渡した値を呼び出すことができるようになります。
下記のコードによって、CountContext.Providerが挟んでいるAppコンポーネントでvalueに渡した{count, addCount}を呼び出し可能になりました。

<CountContext.Provider value={{count, addCount}}>
    <App />
</CountContext.Provider>

下記のコードはコンテキストに直接関係はありませんが念のため内容を説明します。
useStateを使ってステートの値countと、それを更新するための関数setCountを定義します。
そして、ボタンを押した時のイベントハンドラのaddCountを定義します。
内容はステートcountの値に+1する処理です。

const [count, setCount] = useState(0);
const addCount = () => {
  setCount(count + 1);
};

3.useContextフックを使ってデータを取得する

上記まででプロバイダーに渡した値を渡してAppコンポーネントで呼び出すことが可能になりました。次にその値の呼び出し方について説明します。

App.js
export const App = () => {
    // プロバイダーに渡した値を呼び出す
    const {count, addCount} = useContext(CountContext)

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={addCount}>
        Click me
      </button>
    </div>
  );
}

上記の下記の箇所がプロバイダーに渡した値を呼び出している箇所になります。
useContextを使ってCountContextからプロバイダーに渡した値のcount,addCountそれぞれを呼び出しています。

// プロバイダーに渡した値を呼び出す
const {count, addCount} = useContext(CountContext)

以上で説明は終わりです。

また、CountProvider.jsを下記のようにuseMemoを使うことで最適化できます。
 ステートの内容が変わるたびに再レンダリングされるのでステートの数が多くなるとレンダリングのコストが大きくなっていきます。useMemoを使うと最新の値と前の値を比較して必要な箇所だけ計算が行われます。それによってレンダリング毎に複雑な計算をされることを避けることができます。
 詳しく知りたい方は下記の公式ドキュメントを参考にしてください。

CountProvider.js
export const useCount = () => {
  const [count, setCount] = useState(0);
  const addCount = () => {
    setCount(count + 1);
  };
  const providerValue = useMemo(() => ({count, addCount}), [count]);
  return providerValue;
}

const providerValue = useCount();
<CountContext.Provider value={providerValue}>
    <App />
</CountContext.Provider>

https://ja.reactjs.org/docs/react-api.html#reactmemo
https://ja.reactjs.org/docs/hooks-reference.html#usememo

以上です。読んでいただきありがとうございました。
誤字、脱字、間違い等ありましたらコメント頂ければ幸いです。

Discussion