ReactのuseContextを使ってみる

ReactのuseContextを使って、データをグローバルに扱えるようにしてみます。

サンプルコード

今回はLayer1、Layer2、Layer3というコンポーネントを用意して、Layer1からLayer2、Layer2からLayer3をインポートする例で試してみます。
まずは使用前の例で、propsを使ってデータの受け渡しをしてみます。

Layer1.jsx

import Layer2 from './Layer2.jsx'

function Layer1() {
  const text = "sample";
  return (
    <div style={{border: "2px solid red", padding: "10px"}}>
      <p>Layer1</p>
      <Layer2 text={text} />
    </div>
  )
}

export default Layer1

Layer2.jsx

import Layer3 from './Layer3.jsx'

function Layer2({text}) {
  return (
    <div style={{border: "2px solid blue", padding: "10px"}}>
      <p>Layer2</p>
      <Layer3 text={text} />
    </div>
  )
}

export default Layer2

Layer3.jsx

function Layer3({text}) {
  return (
    <div style={{border: "2px solid green", padding: "10px"}}>
      <p>Layer3</p>
      <p>{text}</p>
    </div>
  )
}

export default Layer3

このようにpropsを使ってデータの受け渡しができますが、バケツリレーとなるため深い階層のコンポーネントだと記述が助長になりやすいです。
propsの場合のデモページ

useContextを使うことで、コンポーネント間のデータの受け渡しがしやすくなります。
まずLayer1.jsxでcreateContextを使ってコンテクストを作成して、使用したいコンポーネントをコンテクストプロバイダで囲います。

import { createContext } from 'react'
import Layer2 from './Layer2.jsx'
export const Text = createContext(null);

function Layer1() {
  return (
    <Text.Provider value="sample">
      <div style={{border: "2px solid red", padding: "10px"}}>
        <p>Layer1</p>
        <Layer2 />
      </div>
    </Text.Provider>
  )
}

export default Layer1

今回の場合はTextにコンテクストを作成しているため、使用したいコンポーネント(Layer2)をコンテクストプロバイダ(Text.Provider)で囲い、valueに渡す値を設定しています。

間に入るLayer2.jsxには特に必要な追加はありません。
propsの記述だけ除去しておきます。

import Layer3 from './Layer3.jsx'

function Layer2() {
  return (
    <div style={{border: "2px solid blue", padding: "10px"}}>
      <p>Layer2</p>
      <Layer3 />
    </div>
  )
}

export default Layer2

最後にLayer3.jsxで受け取る設定を追加します。
Layer1からTextをインポートして、useContextで値を取り出します。

import { useContext } from 'react'
import { Text } from './Layer1'

function Layer3() {
  const text = useContext(Text);
  return (
    <div style={{border: "2px solid green", padding: "10px"}}>
      <p>Layer3</p>
      <p>{text}</p>
    </div>
  )
}

export default Layer3

これでLayer1からLayer3に直接データの受け渡しができました。
useContextの場合のデモページ

次にuseStateを使って渡したデータの更新を試してみます。
Layer1.jsxを以下のように変更します。

import { createContext, useState } from 'react'
import Layer2 from './Layer2.jsx'
export const Text = createContext(null);

function Layer1() {
  const [message, setMessage] = useState("sample");
  return (
    <Text.Provider value={message}>
      <div style={{border: "2px solid red", padding: "10px"}}>
        <p>Layer1</p>
        <input
          type="text"
          value={message}
          onChange={e => setMessage(e.target.value)}
        />
        <Layer2 />
      </div>
    </Text.Provider>
  )
}

export default Layer1

useStateを使った形に変更して、Layer1から値を更新できるようにしました。
useStateを使うデモページ

次はuseContextを複数使用する場合を試してみます。
入れ子で囲うようにするといいようです。

import { createContext, useState } from 'react'
import Layer2 from './Layer2.jsx'
export const Text = createContext(null);
export const Label = createContext(null);

function Layer1() {
  const [message, setMessage] = useState("sample");
  const [message2, setMessage2] = useState("test");
  return (
    <Text.Provider value={message}>
      <Label.Provider value={message2}>
        <div style={{border: "2px solid red", padding: "10px"}}>
          <p>Layer1</p>
          <input
            type="text"
            value={message}
            onChange={e => setMessage(e.target.value)}
          />
          <input
            type="text"
            value={message2}
            onChange={e => setMessage2(e.target.value)}
          />
          <Layer2 />
        </div>
      </Label.Provider>
    </Text.Provider>
  )
}

export default Layer1

Layer3.jsxで追加した分も読み込むように変更します。

import { useContext } from 'react'
import { Text, Label } from './Layer1'

function Layer3() {
  const text = useContext(Text);
  const label = useContext(Label);
  return (
    <div style={{border: "2px solid green", padding: "10px"}}>
      <p>Layer3</p>
      <p>{text}</p>
      <p>{label}</p>
    </div>
  )
}

export default Layer3

これで複数のデータの受け渡しができました。
複数データを使用するデモページ

最後にcreateContextの引数についてですが、これはコンテクストプロバイダ(Text.Provider)がない場合の初期値になります。
Text.Providerをなくして試してみます。

import { createContext } from 'react'
import Layer2 from './Layer2.jsx'
export const Text = createContext('default');

function Layer1() {
  return (
    <div style={{border: "2px solid red", padding: "10px"}}>
      <p>Layer1</p>
      <Layer2 />
    </div>
  )
}

export default Layer1

これで試してみると、createContextの引数で設定したdefaultが表示されるのが確認できました。
コンテクストプロバイダがない場合のデモページ

参考サイト

このエントリーをはてなブックマークに追加

関連記事

コメントを残す

メールアドレスが公開されることはありません。
* が付いている欄は必須項目です

CAPTCHA


コメントが承認されるまで時間がかかります。

2025年1月
 1234
567891011
12131415161718
19202122232425
262728293031