Библиотеки React-компонентов, которые остаются удобными по мере роста команд
Библиотеки React-компонентов быстро запутываются, когда несколько команд добавляют свои паттерны. Узнайте, как названия токенов, лимиты вариантов и ревью помогают держать всё простым.

Почему библиотеки начинают захламляться после нескольких команд
Общая библиотека обычно кажется аккуратной, пока её делает одна команда. Проблемы начинаются, когда подключаются вторая и третья команды, и каждой к пятнице нужна маленькая оговорка. Один дополнительный prop для Button выглядит безобидно. Но десять таких решений спустя кнопку уже труднее понять, чем экран, на котором она стоит.
Именно поэтому библиотеки React-компонентов часто обрастают лишним. Команды оптимизируют под свой релиз, а не под то, какой будет библиотека через шесть месяцев. Команде checkout нужен компактный modal. Команде dashboard нужен modal с закреплёнными действиями. Команде settings нужен вариант с собственным заголовком. Вместо одного понятного паттерна библиотека постепенно собирает особые случаи.
Названия расползаются не хуже. Одна команда выбирает «primary» и «secondary». Другая добавляет «brand» и «muted». Третья команда использует «success» там, где первая использовала «positive». По отдельности все эти решения выглядят нормально. Вместе они делают токены и props трудными для угадывания, а люди как раз и гадают, когда документация устаревает.
Потом появляются дубликаты. У вас есть Button, IconButton, ActionButton, GhostButton. У вас есть Card, Panel, Surface, Tile. Они пересекаются на 80 процентов, но у каждого есть одна деталь, которая продлила ему жизнь. Никто не хочет убирать их, потому что какой-то продукт всё ещё на них завязан.
Первые предупреждающие признаки появляются быстро:
- инженеры добавляют props быстрее, чем убирают их
- похожие компоненты отличаются мелкими, труднообъяснимыми деталями
- названия в дизайне и в коде перестают совпадать
- новые коллеги спрашивают, какая версия — «настоящая»
После этого доверие падает. Инженеры перестают в первую очередь брать общую библиотеку и копируют код в папки продукта. Дизайнеры перестают считать, что один и тот же компонент ведёт себя одинаково в разных продуктах. Ревью идут дольше, потому что люди обсуждают историю вместо того, чтобы смотреть на конкретное изменение.
Вот что на самом деле делает всё это хаосом. Когда люди ждут захламления, они строят вокруг него обходные пути, и библиотека портится с каждым дедлайном.
Выбирайте названия токенов, которые можно угадать
Большая часть путаницы с токенами начинается с названий, которые никто не может предсказать. Когда подключается третья команда, ей не нужно гадать, означают ли marketing-blue, blue-2 и primary-alt одно и то же. Если название токена нельзя угадать, люди перестают доверять системе и добавляют свои варианты.
Начните с простых групп, которые почти все уже ожидают: color, space, type и radius. Эти названия скучные, и именно поэтому они работают. В библиотеках React-компонентов скучные названия экономят больше времени, чем умные.
Называйте токены по назначению, а не по hex-значению, кампании бренда или прозвищу команды. Токен цвета должен описывать, где он используется: для текста, поверхности, границы или действия. Если назвать токен #0057ff или sales-blue, вы привяжете имя к моменту, который скоро изменится.
Вот небольшой набор, который легче держать в порядке:
color.text.defaultcolor.bg.surfacespace.4type.body.smradius.md
У каждой группы должна быть одна и та же схема шкалы. Если spacing использует числа, продолжайте использовать числа. Не смешивайте space.4, space.md и space.large. Если type использует схему «роль плюс размер», держите её везде. Если radius использует sm, md и lg, не подмешивайте radius.6, если не хотите, чтобы люди перестали угадывать и начали постоянно лезть в документацию.
Размытые названия быстро устаревают. blue-2 говорит только о том, как это выглядит сегодня. primary-alt звучит полезно, но никто не знает, когда его выбирать. В итоге команды используют и то и другое для разных случаев, и библиотека начинает расползаться в стороны.
Есть полезное правило: каждый токен должен отвечать на один вопрос простыми словами. Для цвета — «для чего это?». Для spacing — «какой это шаг?». Для type — «какая это текстовая роль?». Для radius — «насколько это скруглено?»
Если новая команда не может прочитать токен и сделать нормальное первое предположение, переименуйте его до того, как он разойдётся дальше. Такая маленькая чистка дешевле, чем потом исправлять пятьдесят компонентов.
Ставьте жёсткие границы для вариантов
Большая часть захламления начинается с разумной просьбы. Одна команда просит спокойную кнопку, другая хочет promo card, и вскоре у простого компонента уже 14 комбинаций, которые никто не может запомнить.
Библиотеки React-компонентов становятся сложными, когда каждое дизайнерское решение превращается в новый вариант. Хорошее правило простое: добавляйте вариант только тогда, когда как минимум два продукта нуждаются в одной и той же опции по одной и той же причине. Если особый стиль нужен только одному экрану, оставьте его локальным.
Размеры требуют той же дисциплины. Люди помнят small, medium и large. Они не помнят xs, sm, md, lg, xl, compact, roomy и hero. Если компоненту нужно больше двух-трёх размеров, проблема часто в раскладке, а не в визуальном стиле.
Отделяйте выбор раскладки от внешнего вида. Card может быть filled или outlined, но ширина, выравнивание и отступы должны приходить от родительской раскладки. Когда команды смешивают эти идеи в одном prop, появляются значения вроде promoWideCentered. Это не переиспользуемый выбор. Это решение для страницы, спрятанное внутри компонента.
Кампанийные стили создают много шума. Сезонные цвета, бейджи запуска и особые решения для лендингов обычно живут несколько недель. Им место в локальных обёртках или стилях страницы, а не в общих buttons, cards или banners. Иначе библиотека превращается в склад старых идей.
Короткая чистка раз в несколько месяцев помогает держать лимиты вариантов честными:
- проверяйте, какие варианты действительно есть на продакшн-экранах, а не только в story-файлах
- объединяйте варианты, которые выглядят по-разному в Figma, но ведут себя одинаково в продукте
- удаляйте варианты, у которых нет текущего использования и нет второй команды, которая их просит
Общий Button — хороший тест. Команда dashboard использует primary и secondary. Команде admin ещё нужен danger state. Они должны быть в библиотеке, потому что ими могут пользоваться больше чем один продукт. А если команде growth нужен неоновый градиентный button для одной кампании, держите его отдельно. Через шесть месяцев никому не придётся гадать, почему у базового Button до сих пор есть забытый prop launchSpring.
Делайте API компонентов простыми и понятными
API компонента должен выглядеть очевидным ещё до того, как кто-то откроет документацию. Если Button принимает size, tone, loading и icon, большинство людей сможет угадать, что делает каждый prop. В этом и есть цель. В библиотеках React-компонентов простые названия живут дольше, чем умные, потому что новые команды не разделяют один и тот же контекст и один и тот же дизайн-жаргон.
Привяжите один prop к одному решению. size должен менять размер. tone должен менять визуальный акцент. loading должен управлять состоянием загрузки, а не одновременно отключать кнопку, менять подпись и прятать иконку. Когда один prop делает три вещи, люди перестают доверять компоненту и начинают добавлять исключения.
То же правило важно и для похожих компонентов. Если buttons, badges и alerts выражают намерение, используйте для этой идеи одно и то же название prop. Выберите tone или variant и придерживайтесь его. Не делайте так, чтобы один компонент использовал kind, другой — status, а третий — appearance. Код становится труднее читать, а небольшие различия превращаются в ненужные ошибки.
Вложенные объекты конфигурации сначала выглядят аккуратно, но часто прячут простые выборы за лишней многословностью. button={{ size: 'sm', tone: 'danger' }} читать сложнее, чем size='sm' tone='danger', когда эти значения относятся к одному компоненту. Оставляйте объекты для действительно связанных данных, а не для обычных стилевых опций.
С defaults нужна та же дисциплина. Если Button на одной странице medium, на другой small, а destructive buttons показывают spinner только в некоторых сценариях, люди не смогут предсказать поведение компонента. Задайте defaults один раз в библиотеке. Если команде нужен другой вид в одном месте, сделайте этот выбор явным в коде.
Хорошая проверка прямолинейна: сможет ли новый инженер использовать компонент, не читая его исходники? Если нет, API, скорее всего, делает слишком много. Понятные props почти скучны. Обычно это и есть признак того, что переиспользуемые React-компоненты останутся удобными, когда их начнут применять всё больше команд.
Проведите короткое API-ревью перед merge
Общий компонент становится публичным почти в тот момент, когда его начинает использовать другая команда. Если merge сделать слишком рано, каждое странное название prop и каждая лишняя опция начинают расползаться. Короткое ревью, проведённое в нужный момент, останавливает этот беспорядок до того, как он попадёт в библиотеку.
Держите ревью небольшим. Обычно достаточно одного дизайнера и одного инженера. Большее количество людей часто означает не лучшие решения, а более длинные мнения. Дизайнер проверяет, совпадает ли компонент с системой, которую люди уже знают. Инженер проверяет, остаются ли props понятными, предсказуемыми и удобными для поддержки.
Откройте примеры компонента и таблицу props одновременно. Не начинайте с кода. Сначала смотрите на то, что остальные коллеги действительно увидят. Затем задайте прямой вопрос: что новый коллега угадает первым? Если он угадает size, а prop называется density, исправьте имя. Если неясно, какой prop важнее всего, значит, в API всё ещё слишком много лишнего.
Несколько подсказок помогают провести ревью быстрее:
- Какое использование по умолчанию, если не читать документацию?
- Какие названия prop кажутся очевидными с первого взгляда?
- Какой вариант выглядит слишком специфичным для одной команды?
- Какого состояния ещё не хватает в примерах?
После этого поставьте компонент на реальный экран. Button может выглядеть нормально в изоляции и всё равно ощущаться неправильно внутри формы регистрации, страницы настроек или панели инструментов таблицы. Реальные экраны выявляют проблемы с отступами, неловкие подписи, состояния загрузки и сочетания prop, которые никто не заметил в sandbox.
Заморозьте API, пока команда не напишет примеры использования. Это звучит жёстко, но работает. Если люди не могут показать два-три обычных сценария так, чтобы всё выглядело скучно и понятно, значит, они ещё недостаточно хорошо понимают компонент. В библиотеках React-компонентов скучно — это хороший знак. Он означает, что другие команды смогут использовать компонент без встречи, без Slack-переписки и без долгих объяснений.
Объединяйте изменения, когда примеры читаются чисто, список prop кажется коротким, а оба ревьюера сами пришли бы к тем же выводам.
Простой пример с тремя продуктовыми командами
Обычно Button начинается аккуратно. Команде один нужно несколько базовых вещей, поэтому она добавляет size и tone. Это нормально. Большинству продуктов нужна маленькая кнопка в таблице и большая в форме, а ещё понятный визуальный тон вроде primary или neutral.
Потом приходит команда два. Им нужны иконки без текста для панели инструментов и состояние загрузки для сохранения и отправки. Эти запросы всё ещё подходят базовому Button, потому что они описывают обычное поведение. Кнопка только с иконкой всё равно остаётся кнопкой. Кнопка в состоянии loading всё равно остаётся кнопкой.
<Button size="md" tone="primary" loading>
Save changes
</Button>
<Button size="sm" tone="neutral" iconOnly aria-label="Search">
<SearchIcon />
</Button>
Проблемы начинаются с команды три. Им нужна кнопка для кампании с кастомными цветами, дополнительным свечением, бейджем и другим spacing для одного запуска. Если это превращается в tone='summer-sale' в основной кнопке, библиотека быстро захламляется. В следующем месяце другая команда попросит tone='holiday', потом tone='partner', и скоро никто уже не будет понимать, какие tone — это реальные стили продукта, а какие пришли из разовой кампании.
Лучше оставить базовую Button маленькой и вынести особый случай в обёртку.
function CampaignButton(props) {
return (
<Button
size="lg"
tone="primary"
className="campaign-button"
{...props}
/>
)
}
Теперь базовый API остаётся лёгким для угадывания: size, tone, loading, поведение кнопки только с иконкой. Команда кампании всё равно получает то, что ей нужно, но странный стиль живёт в CampaignButton, где ему и место. Если кампания закончится, команда сможет удалить или изменить эту обёртку, не трогая каждый другой экран.
Это хороший тест для библиотек React-компонентов. Общее поведение должно попадать в общий компонент. Краткосрочный внешний вид должен оставаться вне его. Если prop звучит так, будто он привязан к одной команде, одному запуску или одной странице, не кладите его в Button.
Ошибки, из-за которых всё захламляется
Большая часть захламления в библиотеках React-компонентов начинается с обходного пути, который в моменте казался безобидным. Одна команда спешит, другая не хочет трогать общий код, а третья добавляет ещё одно исключение. Через пару месяцев библиотека всё ещё работает, но никто ей не доверяет.
Копирование компонента вместо исправления общего — обычно первая трещина. Команде нужен Button со состоянием loading, ждать ревью не хочется, и рядом с основным button появляется CheckoutButton или BillingButton. Такая копия очень быстро уходит в сторону. В одном месте меняются отступы, в другом — стили фокуса, а исправления багов перестают доходить до остальных.
Названия вариантов по командам, брендам или релизам создают другой тип хаоса. Props вроде variant='growth', promo2025 или teamAStyle понятны только тем, кто их придумал. Через шесть месяцев никто не помнит, описывают ли эти названия цвет, намерение, раскладку или временную кампанию. Название должно говорить людям, что делает интерфейс или как он выглядит.
Ещё одна частая ошибка — добавлять props до того, как кто-то подтвердил необходимость. Команды часто говорят: «возможно, это понадобится потом», а затем добавляют флаги для положения иконки, компактных отступов, кастомного padding, особого текста загрузки и разовых границ. Если такое поведение нужно только одному экрану, оставьте его локальным. Общие API должны заслужить каждый prop.
Старые токены и старые props тоже накапливаются, потому что удалять их кажется рискованным. Поэтому команды оставляют и старое имя, и новое, а потом снова сохраняют оба после следующего релиза. Мёртвые опции не бывают безвредными. Они путают новых разработчиков, тормозят ревью и делают рефакторинг страшнее, чем он есть.
Помогает простое правило чистки:
- исправляйте общий компонент до того, как его скопируют
- называйте токены и варианты по смыслу, а не по команде или кампании
- добавляйте prop только после появления второго реального сценария
- назначайте дату удаления для устаревших токенов и props
Примеры важны, но это не полноценный этап ревью. Хорошая история в Storybook всё ещё может скрывать плохой API. Перед merge кто-то должен задать два простых вопроса: угадает ли другая команда это название, и останется ли это понятным после окончания текущего проекта?
Быстрые проверки перед тем, как что-то добавить или изменить
Большая часть захламления в библиотеке начинается с маленького изменения, которое в тот момент казалось безобидным. Для одного экрана добавляется новый prop, рядом появляется чуть другое название компонента, и через полгода никто уже не знает, что выбирать. Пятиминутная проверка перед merge экономит много уборки потом.
Спросите себя, угадает ли новый коллега название компонента с первой попытки. Если ему нужно перебирать Card, InfoCard, PanelCard и FeatureCard, названия уже ушли не туда. Хорошие названия простые и предсказуемые. В библиотеках React-компонентов скучные названия живут дольше, чем умные.
Затем сравните API с похожими компонентами. Если один input использует size, другой — scale, а третий — variant для одной и той же идеи, команды будут копировать ошибки из одного продукта в другой. Последовательность важнее идеальной формулировки. Выберите самое понятное название prop и используйте его повторно.
Прежде чем добавлять новый prop, задайте более жёсткий вопрос: будет ли он нужен хотя бы двум командам в ближайшее время? Если изменение решает один узкий случай для одного продукта, сначала оно, скорее всего, должно жить в локальном коде. Общий код библиотеки должен заслужить своё место.
Многие запросы на стиль вообще не требуют нового prop. Часто проблему можно решить токеном, не расширяя поверхность компонента. Если команде нужен другой spacing или цвет, сначала проверьте набор токенов, а уже потом добавляйте compact, soft или promo props, которые понятны только в одном контексте.
Одна небольшая привычка помогает сильнее, чем ожидают:
- Напишите один пример, показывающий компонент в правильном использовании.
- Напишите один пример, показывающий соблазнительное неправильное использование.
- Прочитайте оба примера вслух.
- Если плохой пример всё ещё кажется разумным, API слишком свободный.
- Если хороший пример требует лишних объяснений, API слишком расплывчатый.
Эта короткая пауза делает всё наглядным. Если команде A нужен banner с более плотными отступами, команде B в следующем месяце нужен такой же banner, а существующих spacing-токенов уже хватает для обоих случаев, добавьте или переиспользуйте токен. Не создавайте dense prop только потому, что так кажется быстрее.
Этот короткий паузу помогает переиспользуемым React-компонентам оставаться понятными вместо того, чтобы медленно превращаться в коробку с исключениями.
Что делать дальше
Начните с того, к чему люди прикасаются каждый день. Соберите десять самых используемых компонентов в один документ и перечислите все props, которые они открывают. Дубли быстро становятся заметны: size и buttonSize, tone и variant, compact и dense. Так у вас появится список на очистку, основанный на реальном использовании, а не на догадках.
Затем сделайте на этот месяц короткую заморозку. Отметьте токены и варианты, которые уже путают людей, и перестаньте добавлять к ним новое, пока кто-то не проверит названия. Короткая заморозка звучит строго, но она предотвращает ещё один месяц дрейфа.
Используйте несколько правил, которые легко запомнить:
- Для каждого нового публичного API нужна одна короткая фраза о том, когда его использовать.
- Если новый prop пересекается со старым, объедините их или отклоните новый.
- Если вариант нужен только одному экрану, оставьте его локальным, пока его не попросит другая команда.
- Названия токенов должны описывать назначение, а не одну визуальную деталь.
- Когда название кажется слишком умным, замените его на простую версию.
Один человек должен иметь последнее слово в вопросах именования и очистки. Это не значит, что всю работу делает один человек. Это значит, что кто-то может сказать «нет», удалить дубликаты и не дать спорам растянуться на недели. Библиотеки React-компонентов намного легче использовать, когда понятно, кто за них отвечает.
Если ваша библиотека уже кажется переполненной, не пытайтесь исправить всё сразу. Сначала проверьте десять самых важных компонентов, заморозьте самые острые проблемы с токенами и вариантами и применяйте своё правило API к каждому новому изменению дальше. Через месяц библиотека обычно становится спокойнее и предсказуемее.
Внешний аудит может помочь, когда команда слишком близко к проблеме. Консультации Fractional CTO от Oleg Sotnikov могут помочь упростить правила компонентов, именование и ответственность, особенно командам, которым нужен ясный технический курс без построения тяжёлого процесса вокруг этого.