PassFront
  1. PassFront
  2. База знаний
  3. SOLID во фронтенде

Как соблюдать принцип открытости/закрытости в UI: расширять компонент без изменения его кода?

SOLID во фронтенде

OCP в UI: компонент расширяют через children, слоты-пропсы, render-функции и конфигурацию, а не добавляя в него новый булев флаг под каждый случай.

Антипаттерн

<Modal showFooter isDanger withCloseIcon hasSecondaryButton /> — каждый новый макет даёт новый проп и новую ветку if внутри. Флаги комбинируются в 2^n состояний, большинство из которых никто не проверял.

Способы расширения

  • children — потребитель сам решает, что внутри.
  • Слоты — именованные пропсы типа ReactNode: header, footer, icon.
  • Render-функции — когда слоту нужны данные компонента: renderItem(item, index).
  • Конфигурация/реестр — columns: ColumnDef[] или карта { [type]: Component }: новый тип поля формы — новая запись, а не правка switch.
  • Compound components — <Tabs.List>, <Tabs.Panel> с общим контекстом.
/** @param {{ title: ReactNode, footer?: ReactNode, children: ReactNode }} props */
function Card({ title, footer, children }) {
  return (
    <section className="card">
      <header>{title}</header>
      <div>{children}</div>
      {footer && <footer>{footer}</footer>}
    </section>
  );
}

Граница

Слишком открытый компонент ломает консистентность дизайн-системы: если в footer кладут что угодно, кнопки разъезжаются. Открывают только оси, где вариативность нужна на деле.

Коротко для собеседования

Компонент открывают через children, слоты, render-пропсы и конфигурацию, а не копят булевы флаги с ветками if. Предельный случай — headless-библиотеки вроде Radix, отдающие потребителю всю разметку; открывать стоит только оси реальной вариативности, иначе дизайн-система расползается.

Другие вопросы раздела