YASD-TECH
YASD TECH
# Next.js
# TypeScript

useContextの使い方

投稿日:2024/10/29

更新日:2024/10/29

ttitleImage

前置き

現場でちょいちょい出てくるのでアウトプットです

利用シーン

例えば親コンポーネントの中にコンポーネント1があり、コンポーネント1の中にコンポーネント2、コンポーネント2の中にコンポーネント3があるとします。

この場合、useContextを使わないケースでは親コンポーネントで設定した値はpropsでコンポーネント1=>コンポーネント2=>コンポーネント3のように渡す必要があります。

これだともっとコンポーネントが増えた時に辛くなります。そういったシーンで利用します。

useContextを使用すると、親コンポーネントで設定した値を直接子コンポーネントで使用することができます。これにより、中間のコンポーネントを経由せずにデータを受け渡すことができ、コードの簡潔さと保守性が向上します。

useContextの主な利点:

  • プロップドリリング(props drilling)の回避
  • コンポーネント間のデータ共有の簡素化
  • グローバルな状態管理の実現

ただし、useContextの使用は適切なシーンで行うべきです。頻繁に変更される値や、アプリケーション全体で使用されない値には、他の状態管理方法を検討することも重要です。

使い方

親コンポーネントの中にコンポーネント1があり、コンポーネント1の中にコンポーネント2、コンポーネント2の中にコンポーネント3がある場合に、親コンポーネントで設定したthemeという値をuseContextを利用してコンポーネント3で取得してみます。

やること

親コンポーネント

  • createContextでコンテキスト作成
  • 作成したコンテキストのプロバイダーで必要な箇所をラップ、valueに子要素で使いたいもの渡す

値を利用したい子コンポーネント

  • useContextで設定した値受け取る

といった感じです。実際コードでみてみましょう。

親コンポーネント

page.tsx
'use client';

import Sample1 from '@/components/Sample1';
import { createContext, useState } from 'react';

// createContextでコンテキスト作成
export const themeContext = createContext<string>('white');

// 作成したコンテキストのプロバイダーで必要な箇所をラップ、valueに子要素で使いたいもの渡す
export default function Home() {
  const [theme, setTheme] = useState<string>('white');

  return (
  
    <themeContext.Provider value={theme}>
      <Sample1 />
      <div className="flex items-center mb-4">
        <input onChange={() => setTheme('dark')} type="radio" name="theme" />
        <label htmlFor="default-radio-1">dark</label>
      </div>
      <div className="flex items-center">
        <input onChange={() => setTheme('white')} type="radio" name="theme" />
        <label htmlFor="default-radio-2">white</label>
      </div>
    </themeContext.Provider>
  );
}

子コンポーネントたち

Sample1.tsx
import Sample2 from '@/components/Sample2';

const Sample1 = () => {
  return <Sample2 />;
};

export default Sample1;

Sample2.tsx
import Sample3 from '@/components/Sample3';

const Sample2 = () => {
  return <Sample3 />;
};

export default Sample2;

利用コンポーネント

Sample3.tsx
import { themeContext } from '@/app/page';
import { useContext } from 'react';

const Sample3 = () => {
  // useContextで設定した値受け取る
  const theme = useContext(themeContext);
  return (
    <>
      <p>{theme}</p>
    </>
  );
};

export default Sample3;

とこんな感じでやるとラジオボタンで設定した値がコンポーネント3で表示できると思います。

これだけだと面白くないので、親コンポーネントを以下のように変更すればバックグラウンドカラーを変えてみましょう。

page.tsx
'use client';

import Sample1 from '@/components/Sample1';
import { createContext, useState } from 'react';

export const themeContext = createContext<string>('white');

export default function Home() {
  const [theme, setTheme] = useState<string>('white');

  return (
    <themeContext.Provider value={theme}>
      <div
        className={`flex flex-col items-center justify-center min-h-screen transition-colors duration-500 ${
          theme === 'dark' ? 'bg-gray-900 text-white' : 'bg-white text-gray-900'
        }`}
      >
        <Sample1 />
        <div className="flex items-center mb-4">
          <input
            onChange={() => setTheme('dark')}
            type="radio"
            name="theme"
            className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
          />
          <label
            htmlFor="default-radio-1"
            className="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300"
          >
            dark
          </label>
        </div>
        <div className="flex items-center">
          <input
            onChange={() => setTheme('white')}
            type="radio"
            name="theme"
            className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
          />
          <label
            htmlFor="default-radio-2"
            className="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300"
          >
            white
          </label>
        </div>
      </div>
    </themeContext.Provider>
  );
}

まとめ

今回は利用方法についてのみまとめましたがこういうグローバル系はレンダリングの最適化に良くなかったりもするので利用シーンは考えないとなぁと思いました。

Index

  • 前置き
  • 利用シーン
  • 使い方
  • やること
  • まとめ