【React】useContextをいつ使う?別ファイルとデータ共有や再レンダリングについて

2022年12月31日React

ReactのuseContextについて、使い方や、いつ使うのかといった情報を共有します。
また、useContextを使って別ファイルとデータ共有の仕方や再レンダリングについても紹介します。

ReactのuseContextについて

useContextを使うことで、値をグローバルに管理することができます。
使い方は後述するとして、まずはいつ使うのかといった使い所を確認しましょう。

ReactのuseContextっていつ使うの?

ReactのuseContextは、値をグローバルに管理したいときです。
具体的なケースとしては、以下のようなケースです。

Sample.js(親コンポーネント)
components/Child.js(子コンポーネント)
components/GrandChild.js(孫コンポーネント)

親コンポーネントで設定した値を、子コンポーネントでは使用せず、孫コンポーネントで使用したいとします。
その場合、useContextを使わない場合はpropsでバケツリレーして、子コンポーネントにpropsで渡して孫コンポーネントで使用します。
これをpropsのバケツリレーといったりします。
propsのバケツリレーが増えてくると、
間にあるコンポーネントで使わないpropsを渡すだけなので、どのpropsをどのファイルで使っているのかがわかりにくくなります。
このようなときに、useContextを使います。
では実際にコードで確認してみましょう。

ReactのuseContextの使い方

useContext使用前

Sample.js(親コンポーネント)

import Child from "./components/Child";

const Sample = () => {
  const value = '孫コンポーネントで使いたい値'
  return <Child value={value}/>;
};

export default Sample;

components/Child.js(子コンポーネント)

import GrandChild from "./GrandChild";

const Child = ({ value }) => (
  <div>
    <h3>子コンポーネント</h3>
    <GrandChild value={value} />
  </div>
);

export default Child;

components/GrandChild.js(孫コンポーネント)

const GrandChild = ({ value }) => {
  return (
      <div>
        <h3>孫コンポーネント</h3>
        {value}
      </div>
  );
};
export default GrandChild;

useContext使用後

Sample.js(親コンポーネント)

import { createContext } from "react";
import Child from "./components/Child";
export const MyContext = createContext("孫コンポーネントで使いたい値");

const Sample = () => {
  return <Child />;
};

export default Sample;

まず、useContextで値を使用するためには、親のコンポーネントで渡したい値をcreateContextで指定する必要があります。
子コンポーネントにはpropsを渡す必要がなくなります。

components/Child.js(子コンポーネント)

import GrandChild from "./GrandChild";

const Child = () => (
  <div>
    <h3>子コンポーネント</h3>
    <GrandChild />
  </div>
);

export default Child;

子コンポーネントでは使わないpropsを受け取り必要も渡す必要もなくなり、よりスッキリしたコードとなります。

components/GrandChild.js(孫コンポーネント)

import { useContext } from "react";
import { MyContext } from "../Sample";

const GrandChild = () => {
  const value = useContext(MyContext);

  return (
    <div>
      <h3>孫コンポーネント</h3>
      {value}
    </div>
  );
};
export default GrandChild;

孫コンポーネントで使いたいので、createContextで作成された変数を読み込みます。
そして、useContextをreactからインポートします。
あとは、useContextに使いたい値をセットして、それを変数として使うだけです。
これが一番シンプルな使い方となります。

useContextでstateの値を使う方法

Sample.js(親コンポーネント)←ここでcreateContext
Child.js(子コンポーネント)
GrandChild.js(孫コンポーネント)←ここでuseContext
OtherChild.js(他の子コンポーネント)←ここでuseContext
ある親コンポーネントの孫コンポーネントと他の子コンポーネントで同じstateを使いたい場合の書き方をみてみましょう。

useContext使用後

Sample.js(親コンポーネント)

import { useState, createContext } from "react";

import Child from "./components/Child";
import OtherChild from "./components/OtherChild";
export const MyContext = createContext();

const Sample = () => {
  const [state, setState] = useState(0);

  return (
    <MyContext.Provider value={[state, setState]}>
      <Child />
      <OtherChild />
    </MyContext.Provider>
  );
};

export default Sample;

createContextのProviderで使いたいコンポーネントをラップします。
そのProviderに渡した値をuseContextで使用できるようになります。
上のように、useStateの左辺を配列のまま、valueに設定します。
useContextの挙動は順々に階層を上がって、createContextのProviderがみつかったらその値を取得します。

Child.js(子コンポーネント)

import GrandChild from "./GrandChild";

const Child = () => (

  <div style={{ border: "3px solid black", padding: 15 }}>
    <h3>子コンポーネント</h3>
    <GrandChild />
  </div>
);
export default Child;

子コンポーネントは孫コンポーネントを読み込みたいだけなので、特にやることはありません。

GrandChild.js(孫コンポーネント)

import { useContext } from "react";
import { MyContext } from "../Sample";
const GrandChild = () => {
  const [state] = useContext(MyContext);

  return (
    <div style={{ border: "3px solid black", padding: 15 }}>
      <h3>孫コンポーネント</h3>
      {state}
    </div>
  );
};
export default GrandChild;

useContextで受け取りたいstateを指定します。
分割代入でやると便利で、受け取るときに自由に名前を変更できます。

OtherChild.js(他の子コンポーネント)

import { useContext } from "react";
import { MyContext } from "../Sample";

const OtherChild = () => {
  const [state, setState] = useContext(MyContext);

  const clickHandler = (e) => {
    setState((prev) => prev + 1);
  };

  return (
    <div>
      <h3>他の子コンポーネント</h3>
      <button onClick={clickHandler}>+</button>
      <h3>{state}</h3>
    </div>
  );
};

export default OtherChild;

こちらも孫コンポーネントと同様です。
更新用関数だけ必要な場合は、const [, setState] = useContext(MyContext);と分割代入で記述します。

createContextとuseContextの実例

モーダルで値をアプリ全体で使えるようにしているカスタムフックの記事を参考にしてみてください。

React

Posted by devsakaso