Children и вложенные элементы

MDX расширяет возможности JSX, позволяя включать Markdown-разметку внутрь компонентов и наоборот. Одним из ключевых аспектов работы с компонентами в MDX является использование свойства children и работа с вложенными элементами.

Передача содержимого через children

В React компоненты могут получать дочерние элементы через проп children. MDX сохраняет этот принцип, позволяя вставлять текст, другие компоненты или Markdown-блоки внутрь компонента. Например:

<MyComponent>
  Это простой текст внутри компонента.
</MyComponent>

В этом случае компонент MyComponent получит в своих пропсах объект children, содержащий текстовый узел.

Для доступа к children используется стандартная деструктуризация пропсов:

export default function MyComponent({ children }) {
  return <div className="my-component">{children}</div>;
}

Результат отобразит весь переданный контент, сохраняя разметку, если это Markdown:

<MyComponent>
  # Заголовок внутри компонента
  Текст с **жирным** выделением
</MyComponent>

Вложенные компоненты

MDX позволяет комбинировать JSX и Markdown, что дает возможность использовать компоненты внутри других компонентов и передавать их через children. Например:

<Container>
  <Header title="Вложенный компонент" />
  <p>Описание внутри контейнера</p>
</Container>

Компонент Container может обрабатывать вложенные элементы любым удобным образом:

export function Container({ children }) {
  return <section className="container">{children}</section>;
}

Важно помнить, что children в MDX может содержать:

  • Текстовые узлы
  • Элементы Markdown (<p>, <h1>, <ul> и т.д.)
  • JSX-компоненты
  • Фрагменты, состоящие из нескольких элементов

Динамическая обработка children

Для более сложных сценариев MDX позволяет анализировать и модифицировать дочерние элементы внутри компонента. Можно использовать функции React.Children для перебора, фильтрации или изменения дочерних узлов:

import React from 'react';

export function HighlightParagraphs({ children }) {
  const highlighted = React.Children.map(children, child => {
    if (child.type === 'p') {
      return <p style={{ backgroundColor: 'yellow' }}>{child.props.children}</p>;
    }
    return child;
  });

  return <div>{highlighted}</div>;
}

MDX с этим компонентом будет подсвечивать только абзацы, сохраняя структуру остальных элементов:

<HighlightParagraphs>
  <p>Этот абзац будет подсвечен</p>
  <MyComponent>Компонент останется без изменений</MyComponent>
</HighlightParagraphs>

Вложенные функции и рендер-пропсы

MDX поддерживает передачу функций через children, аналогично паттерну render-props в React. Это особенно полезно для генерации динамического контента внутри компонентов:

<DataList>
  {data => (
    data.map(item => <li key={item.id}>{item.name}</li>)
  )}
</DataList>

Компонент DataList получает функцию как children и может вызывать её с нужными данными:

export function DataList({ children }) {
  const data = [{ id: 1, name: 'Элемент 1' }, { id: 2, name: 'Элемент 2' }];
  return <ul>{children(data)}</ul>;
}

Контекст и children

MDX хорошо интегрируется с React Context. Вложенные элементы могут получать данные из контекста, даже если они находятся глубоко внутри структуры MDX:

import { createContext, useContext } from 'react';

const ThemeContext = createContext('light');

export function ThemeProvider({ children }) {
  return <ThemeContext.Provider value="dark">{children}</ThemeContext.Provider>;
}

export function ThemedText({ children }) {
  const theme = useContext(ThemeContext);
  return <span style={{ color: theme === 'dark' ? 'white' : 'black' }}>{children}</span>;
}

Использование в MDX:

<ThemeProvider>
  <ThemedText>Этот текст будет тёмным</ThemedText>
</ThemeProvider>

Особенности рендеринга Markdown внутри children

MDX преобразует Markdown в JSX, поэтому все передаваемые через children Markdown-элементы становятся React-узлами. Это означает, что можно использовать комбинацию Markdown и компонентов:

<MyComponent>
  ## Заголовок Markdown
  - Список
  - Элемент
  <SubComponent>Вложенный компонент</SubComponent>
</MyComponent>

React-узлы сохраняют вложенность и позволяют компоненту полностью контролировать визуализацию содержимого.

Практические рекомендации

  • Использовать React.Children для перебора и фильтрации дочерних элементов при необходимости модификации.
  • Для сложной разметки комбинировать Markdown и JSX, сохраняя читаемость MDX-файла.
  • При динамическом рендере передавать функции через children, чтобы компонент мог сам решать, как отображать данные.
  • Вложенные компоненты и контексты работают без ограничений, позволяя создавать гибкие и масштабируемые интерфейсы.

Работа с children в MDX позволяет создавать высоко модульные и настраиваемые компоненты, комбинируя Markdown и JSX в единый поток рендеринга. Это обеспечивает мощный инструмент для построения интерактивной и динамичной документации или контентных приложений.