LoginSignup
4
2

More than 3 years have passed since last update.

5分でわかる useContext の使い方【TypeScriptまで】

Last updated at Posted at 2020-09-11

できるだけシンプルに useContext の使い方を解説。

useContextとはそもそも何

useContext とは親より全ての子(孫)がプロパティや値をグローバルに扱えるようにする Hook(または親以下をスコープにするHookとも言える)。
したがって、親に埋め込まれていないコンポーネントへは値を渡すことはできない。

useState と合わせて使うことで props のバケツリレーをせずに状態を更新できるようになるのがメリット。
バケツリレーの複雑さを避けるために使えるかと。

使い方

  1. createContext() で親に初期値を渡す(createContextをimport)
  2. useContext() で子や孫で受け取る(useContextをimport)

単純なサンプル

Parent.js
Child.js
ChildChild.js
ChildChildChild.js
で親から孫のファイルを作った。ネストさせてコンポートネントを埋め込んでいる。
まずは useState などは使わずに使ってみることに。

Parent.js では createContext で初期値を設定している。宣言した 変数Context がグローバルで扱える変数となる。

Parent.js
import React, { createContext } from "react";
import Child from "./Child";

export const Context = createContext("私はContextです。propsで渡してもらっていません。");

const Parent = () => (
    <>
      <h1>親です</h1>
      <Child />
    </>
 );

export default Parent;

Child.js以降では useContext(Context) で 親の createContext を使って宣言した 変数Context を呼び出すことができる。

Child.js
import React, { useContext } from "react";
import ChildChild from "./ChildChild";
import { Context } from "./Parent";

const Child = () => {
  const ChildContext = useContext(Context);
  return (
    <>
      <h2>Childです</h2>
      <p>{ChildContext}</p>
      <ChildChild />
    </>
  );
};
export default Child;

ChildChild.js
import React, { useContext } from "react";
import ChildChildChild from "./ChildChildChild";
import { Context } from "./Parent";

const ChildChild = () => {
  const ChildChildContext = useContext(Context);

  return (
    <>
      <h2>ChildChildです</h2>
      <p>{ChildChildContext}</p>
      <ChildChildChild />
    </>
  );
};

export default ChildChild;

ChildChildChild.js
import React, { useContext } from "react";
import { Context } from "./Parent";

const ChildChildChild = () => {
  const ChildChildChildContext = useContext(Context);

  return (
    <>
      <h2>ChildChildChildです</h2>
      <p>{ChildChildChildContext}</p>
    </>
  );
};

export default ChildChildChild;

このようにpropsを使わずに値を呼び出すことができた。

useContextの値の更新

今度は先ほどのサンプルを元に useState と合わせて使う。
といっても useState で状態を設定したら親側に Context.Provider というタグを埋め込みそこに state を設定するだけ。

codesandbox: https://codesandbox.io/s/weathered-dawn-buyky?fontsize=14&hidenavigation=1&theme=dark

Parent.js
import React, { useState, createContext } from "react";
import Child from "./Child";

export const Context = createContext();

const Parent = () => {
  const [state, setState] = useState(
    "私はContextです。propsで渡してもらっていません。"
  );
  const updateContext = () => setState("Contextを更新したよ。");

  return (
    <>
      <h1>親です</h1>
      <button onClick={updateContext}>contextを更新するボタン</button>
      <Context.Provider value={state}>
        <Child />
      </Context.Provider>
    </>
  );
};

export default Parent;

Parent.js
      <button onClick={updateContext}>contextを更新するボタン</button>
      <Context.Provider value={state}>
        <Child />
      </Context.Provider>

更新ボタンで state を更新させる。
Context.Provider のタグは子コンポーネントを囲ってあげる。

Provider で設定された value が親より以下コンポーネントが参照する useContext の値となるのでそこにstateを設定すれば当然、状態を親以下のスコープで更新することができるようになる。

TypeScriptでuseContextを使う

こちらもcodesandboxでサンプルを用意した
https://codesandbox.io/s/optimistic-sea-x9c95?fontsize=14&hidenavigation=1&theme=dark)

Parent.tsx
import React, { FC, createContext, useState } from "react";
import Child from "./Child";

export type ContextType = string;
export const Context = createContext<ContextType>("");

const Parent: FC = () => {
  const [state, setState] = useState(
    "私はContextです。propsで渡してもらっていません。"
  );
  const updateContext = () => setState("Contextを更新したよ。");

  return (
    <>
      <h1>親です</h1>
      <button onClick={updateContext}>contextを更新するボタン</button>
      <Context.Provider value={state}>
        <Child />
      </Context.Provider>
    </>
  );
};

export default Parent;

Context を宣言するタイミングで型を付けてあげる

Parent.tsx
export type ContextType = string;
export const Context = createContext<ContextType>("");

type ContextType = string; と解説用に用意しているがオブジェクトなどの型を用意しておき、createContext と共に型を当てはめておきたい。

TypeScriptのuseContextの蛇足

export const Context = createContext<Partial<ContextType>>({});

蛇足として使ったことはないものの、オブジェクトを初期化する場合は Partial を使うことで初期化できるとのこと。
参考:Make useContext Data More Discoverable with Typescript

まとめてみた所感

useState との兼ね合いがわかりにくかったが記事において useContext 単体での動きと切り分けてまとめてみる比較的にシンプルな Hook だと思った。
あくまで useContext(createContex) はプロパティや値のスコープ拡張をするもの。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2