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フィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Contextを使った複合コンポーネント
- Render PropsとHOCパターン
- モーダルとツールチップのためのPortal
- エラーバウンダリー