0Pricing
Frontend Academy · Урок

Составные компоненты с Context

Передавайте неявное состояние между родительским компонентом и его назначенными дочерними компонентами с помощью Context, моделируя API вроде и

«Составные компоненты с Context» — бесплатный урок Frontend Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Frontend Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Frontend Academy содержит 4 уроков всего.

Что такое составные компоненты

Составные компоненты — это набор связанных компонентов, предназначенных для совместной работы как единое целое, например HTML-элементы <select> и <option>. Родительский компонент передаёт дочерним компонентам неявное состояние.

Цель: более чистые API

Вместо <Select options={[...]} value={x} onChange={...} /> Вы пишете <Select><Option value="a">Apple</Option></Select>. Такая структура декларативна и естественно использует JSX.

Наивный подход: проблема

Передача состояния через свойства требует от пользователя связать всё вручную. Дочерние компоненты не получают сведения о состоянии родителя автоматически.

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

Контекст как связующее звено

Родительский компонент создаёт Context с общим состоянием и предоставляет его. Дочерние компоненты используют контекст — явная передача свойств не требуется.

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>
  );
}

Дочерние компоненты используют контекст

Каждый дочерний компонент читает данные из контекста — свойства не приходится передавать через всё дерево.

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 содержит дочерние компоненты 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 для общего состояния: Provider в родительском компоненте, useContext в дочерних. Присоединяйте вложенные компоненты как статические свойства, чтобы их было легко находить. Экспортируйте пользовательский хук как публичный API. Radix и Headless UI — отличные источники примеров. Предпочитайте контекст анализу Children.

Часто задаваемые вопросы

Урок «Составные компоненты с Context» бесплатный?

Да — полный текст урока «Составные компоненты с Context» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Frontend Academy, подпишись на CoddyKit PRO. Курс Frontend Academy содержит 4 уроков всего.

Чему я научусь в уроке «Составные компоненты с Context»?

Передавайте неявное состояние между родительским компонентом и его назначенными дочерними компонентами с помощью Context, моделируя API вроде и Ты практикуешь Frontend Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Frontend Academy?

Предыдущий опыт не требуется. Frontend Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Составные компоненты с Context»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Frontend Academy?

Да. Каждый урок Frontend Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Составные компоненты с Context
  2. Свойства рендеринга и шаблоны HOC
  3. Порталы для модальных окон и подсказок
  4. Границы ошибок
← Назад к Frontend Academy