0Pricing
Frontend Academy · レッスン

Contextを使った複合コンポーネント

Contextを使って親コンポーネントと指定した子コンポーネントの間で暗黙的な状態を共有し、 や のようなAPIをモデル化します。

「Contextを使った複合コンポーネント」はCoddyKit上の無料Frontend Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはFrontend Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Frontend Academyコースには全4レッスンが含まれています。

複合コンポーネントとは

複合コンポーネントとは、HTMLの<select>と<option>のように、1つの単位として連携するよう設計された関連コンポーネントの集合です。親は、特定の子と暗黙的に状態を共有します。

目標:より明快なAPI

<Select options={[...]} value={x} onChange={...} />の代わりに、<Select><Option value="a">Apple</Option></Select>と記述します。構造が宣言的になり、JSXの形式に自然に沿ったものになります。

単純なアプローチ(問題点)

propsを通じて状態を渡す場合、利用者がすべてを接続する必要があります。子コンポーネントは、親の状態を自動的には認識しません。

// Without compound pattern — verbose:
<Tabs activeIndex={0} onChange={setIndex}>
  <TabList>
    <Tab index={0}>Home</Tab>
    <Tab index={1}>Profile</Tab>
  </TabList>
</Tabs>

接続役としてのContext

親が共有状態を持つContextを作成して提供します。子コンポーネントはContextを利用するため、明示的にpropsを接続する必要がありません。

import { createContext, useContext, useState } from 'react';

const TabsContext = createContext(null);

export function Tabs({ children, defaultIndex = 0 }) {
  const [activeIndex, setActiveIndex] = useState(defaultIndex);
  return (
    <TabsContext.Provider value={{ activeIndex, setActiveIndex }}>
      <div className="tabs">{children}</div>
    </TabsContext.Provider>
  );
}

子コンポーネントによる利用

各子コンポーネントはContextから読み取るため、ツリーを通じてpropsを渡す必要がありません。

export function Tab({ index, children }) {
  const { activeIndex, setActiveIndex } = useContext(TabsContext);
  const isActive = activeIndex === index;
  return (
    <button
      className={isActive ? 'active' : ''}
      onClick={() => setActiveIndex(index)}
    >
      {children}
    </button>
  );
}

export function Panel({ index, children }) {
  const { activeIndex } = useContext(TabsContext);
  if (activeIndex !== index) return null;
  return <div className="panel">{children}</div>;
}

見つけやすさのための静的プロパティ

サブコンポーネントを親に割り当てると、ユーザーはオートコンプリートから見つけられます。

Tabs.Tab = Tab;
Tabs.Panel = Panel;

// Usage:
<Tabs>
  <Tabs.Tab index={0}>Home</Tabs.Tab>
  <Tabs.Tab index={1}>Profile</Tabs.Tab>
  <Tabs.Panel index={0}>Home content</Tabs.Panel>
  <Tabs.Panel index={1}>Profile content</Tabs.Panel>
</Tabs>

実例:Disclosure

Disclosureウィジェットには、Contextを通じて開閉状態を共有するTriggerとPanelの子コンポーネントがあります。

function Disclosure({ children }) {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <DisclosureContext.Provider value={{ isOpen, setIsOpen }}>
      <div>{children}</div>
    </DisclosureContext.Provider>
  );
}

function Trigger({ children }) {
  const { isOpen, setIsOpen } = useContext(DisclosureContext);
  return <button onClick={() => setIsOpen(o => !o)}>{children}</button>;
}

function Panel({ children }) {
  const { isOpen } = useContext(DisclosureContext);
  return isOpen ? <div>{children}</div> : null;
}

公開APIとしてのフック

カスタムフックをエクスポートすると、ユーザーはそれを基盤に独自のコンポーネントを構築できます。

export function useTabs() {
  const ctx = useContext(TabsContext);
  if (!ctx) throw new Error('useTabs must be used inside <Tabs>');
  return ctx;
}

多相的な複合コンポーネント

asプロパティまたはasChildパターン(Radix UIの方式)を使って、親が任意の要素を描画できるようにします。これにより、複合コンポーネントを任意のJSXと組み合わせられます。

ヘッドレスな複合コンポーネントパターン

ヘッドレスライブラリ(Radix、Headless UI)は、スタイルを持たない複合コンポーネントを提供します。アクセシビリティのロジックが組み込まれており、必要に応じてスタイルを設定できます。

落とし穴:子の検査

以前はReact.Childrenを使って子を検査するパターンがありましたが、壊れやすく脆弱です。状態の共有には常にContextを優先してください。

クイックチェック

複合コンポーネントパターンでは、子コンポーネントはどのように親コンポーネントと通信しますか?

復習:複合コンポーネント

複合コンポーネントを使うと、関連する各部分を1つの宣言的な単位として連携させられます。状態の共有にはContextを使用し、親にProvider、子にuseContextを配置します。サブコンポーネントを静的プロパティとして割り当てると、見つけやすくなります。カスタムフックを公開APIとしてエクスポートします。RadixとHeadless UIは優れた参考例です。Childrenの検査よりもContextを優先してください。

よくある質問

「Contextを使った複合コンポーネント」レッスンは無料ですか?

はい。「Contextを使った複合コンポーネント」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Frontend Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Frontend Academyコースには全4レッスンが含まれています。

「Contextを使った複合コンポーネント」で何を学びますか?

Contextを使って親コンポーネントと指定した子コンポーネントの間で暗黙的な状態を共有し、 や のようなAPIをモデル化します。 ブラウザで直接実行するハンズオンコードでFrontend Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Frontend Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのFrontend Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「Contextを使った複合コンポーネント」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このFrontend Academyレッスンでコードを書いて実行できますか?

はい。すべてのFrontend Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Contextを使った複合コンポーネント
  2. Render PropsとHOCパターン
  3. モーダルとツールチップのためのPortal
  4. エラーバウンダリー
← Frontend Academyに戻る