Каждый, кто пробовал генерировать React-код через LLM, знает этот момент: просишь простой компонент — получаешь полотно с useEffect, useState и useRef там, где хватило бы одного useMemo. Или того хуже — бесконечный цикл ререндеров, который приходится ловить по всему проекту. Проблема не в модели, а в промте: без чётких ограничений LLM скатывается к шаблонному «безопасному» коду, который в React как раз и создаёт проблемы.
Эта подборка — набор промтов, которые я собрал, пока рефакторил три проекта подряд. Они не про «напиши мне компонент», а про то, как заставить модель думать в терминах React-парадигмы: производного состояния, мемоизации, декларативности. Каждый промт — с примером и пояснением, для какой задачи он годится.
Промты для генерации компонентов и хуков
1. Компонент без лишних состояний
Задача: получить функциональный компонент, который не хранит в useState то, что можно вычислить.
Промт:
Ты — React-разработчик, который ненавидит лишние состояния. Напиши компонент [описание]. Жёсткие правила:
- Никаких useEffect для производного состояния.
- Если значение можно вычислить из props или других состояний — вычисляй на рендере, не храни в useState.
- Мемоизируй только там, где есть реальная проблема производительности (обоснуй).
- Покажи дерево состояний: какие данные действительно меняются со временем, а какие производные.
Пример: просите компонент корзины с итоговой суммой. Модель не создаст useState(total), а посчитает items.reduce(...) на рендере. Это убирает целый класс багов рассинхронизации.
Почему работает: вы явно запрещаете паттерн, который LLM считает «нормальным» из-за обучающих данных. Без запрета модель добавит useEffect для обновления суммы при изменении списка — классический антипаттерн.
2. Кастомный хук с чистой логикой
Задача: вынести повторяющуюся логику в хук, который легко тестировать.
Промт:
Создай кастомный хук use[Name] для [задача]. Требования:
- Хук не должен содержать JSX.
- Вся побочная логика — в отдельных функциях внутри хука или рядом.
- Возвращай кортеж или объект с явными именами.
- Добавь JSDoc с описанием каждого возвращаемого значения.
- Напиши пример использования в компоненте.
Пример: useLocalStorage — хук для синхронизации состояния с localStorage. Модель выдаст чистую реализацию с обработкой ошибок парсинга и без useEffect для каждого обновления, если явно указать на подписку через useSyncExternalStore (если версия React позволяет).
Тонкость: в React 18+ для подписок на внешние источники правильнее useSyncExternalStore, а не useEffect + useState. Укажите это в промте — модель учтёт.
useCallback с правильными зависимостями — иначе вы получите новый референс на каждом рендере и сломаете мемоизацию у потребителей.
Промты для борьбы с ререндерами и «useEffect-адом»
3. Аудит компонента на лишние ререндеры
Задача: найти причины частых ререндеров и предложить исправления.
Промт:
Проанализируй код компонента ниже. Найди все причины лишних ререндеров. Для каждой:
- объясни, почему происходит ререндер;
- предложи минимальное изменение (не переписывай всё);
- укажи, какие зависимости в useEffect/useMemo/useCallback неверны.
Выведи в виде таблицы: строка кода → проблема → решение.
Пример: компонент с useEffect(() => setX(...), [obj]), где obj — новый объект на каждом рендере. Модель укажет на нестабильную зависимость и предложит вынести создание объекта в useMemo или использовать примитивы.
Почему это важно: LLM часто не видит проблему, пока вы не попросите её явно искать. Формулировка «найди все причины» переключает режим с генерации на анализ.
4. Замена useEffect на производное состояние
Задача: убрать useEffect, который синхронизирует пропсы и состояние.
Промт:
В коде ниже есть useEffect, который обновляет состояние при изменении пропса. Перепиши компонент так, чтобы этого useEffect не было. Используй один из подходов:
- вычисление на рендере;
- key prop для сброса состояния;
- useMemo для тяжёлых вычислений.
Объясни, почему выбранный подход лучше.
Пример: компонент, который сбрасывает внутреннее состояние при смене userId. Вместо useEffect(() => setValue(''), [userId]) модель предложит использовать key={userId} на компоненте — это идиоматичнее и не создаёт лишнего рендера.
5. Стабилизация колбэков и объектов
Задача: убрать бесконечные циклы из-за нестабильных зависимостей.
Промт:
Покажи, как обернуть колбэк и объект в useCallback и useMemo, чтобы устранить бесконечный цикл в useEffect. Не меняй логику, только мемоизацию. Укажи, какие зависимости должны быть в каждом хуке.
Пример: useEffect(() => { fetchData({ filter }) }, [filter]), где filter — объект. Модель предложит мемоизировать filter или разбить на примитивы.
useMemo и useCallback не предотвращают ререндер компонента — они предотвращают пересоздание значений. Ререндер остановит только React.memo или мемоизация дочерних компонентов. Не путайте эти уровни.
Промты для рефакторинга классовых компонентов
6. Перевод class → function с сохранением поведения
Задача: переписать классовый компонент на хуки без изменения логики.
Промт:
Перепиши классовый компонент ниже на функциональный с хуками. Сохрани всё поведение: жизненный цикл, обработчики, состояние. Для каждого метода жизненного цикла покажи, во что он превращается (componentDidMount → useEffect с пустым массивом и т.д.). Если есть componentDidUpdate с условием — объясни, как сохранить условие.
Пример: компонент с componentDidUpdate(prevProps) и сравнением. Модель покажет, что в функциональном компоненте это делается через useEffect с зависимостями и useRef для предыдущего значения — и предупредит о возможных лишних вызовах.
Trade-off: автоматический перевод может добавить лишние useEffect, если не указать на сохранение поведения. Всегда проверяйте, что модель не заменила shouldComponentUpdate на React.memo без анализа.
7. Разделение большого компонента
Задача: разбить монолитный компонент на части без потери производительности.
Промт:
Разбей компонент ниже на несколько меньших. Предложи структуру: какие части вынести в отдельные компоненты, какие — в хуки. Укажи, где нужен React.memo, а где нет. Не создавай лишних состояний — данные передавай через props.
Пример: компонент с формой и списком. Модель вынесет список в отдельный компонент с React.memo и оставит форму с локальным состоянием.
Промты для тестирования React
8. Тесты с React Testing Library
Задача: сгенерировать тесты, которые проверяют поведение, а не реализацию.
Промт:
Напиши тесты для компонента ниже с использованием React Testing Library и Jest. Правила:
- Не тестируй внутреннее состояние или пропсы напрямую.
- Ищи элементы по роли, тексту или label — не по className или data-testid без необходимости.
- Покрой: рендер, взаимодействие пользователя (click, input), условный рендер.
- Для асинхронных действий используй waitFor.
Пример: тест кнопки, которая меняет текст после клика. Модель напишет screen.getByRole('button', { name: /отправить/i }) и fireEvent.click, а затем проверит screen.getByText(/отправлено/i).
Почему это лучше: явный запрет на тестирование реализации заставляет модель использовать рекомендованный подход из документации Testing Library.
9. Тесты для кастомного хука
Задача: протестировать хук изолированно.
Промт:
Напиши тесты для кастомного хука use[Name] с помощью @testing-library/react-hooks (или renderHook из @testing-library/react). Покрой:
- начальное состояние;
- обновление состояния через возвращаемые функции;
- обработку ошибок;
- очистку (cleanup) при размонтировании.
Пример: хук useFetch — тесты с моком fetch и проверкой статусов загрузки.
act(). Проверьте, что все вызовы, меняющие состояние, находятся внутри act или waitFor.
Промты для типизации и рефакторинга пропсов
10. Типизация пропсов без any
Задача: получить строгие типы для компонента.
Промт:
Напиши интерфейс Props для компонента ниже на TypeScript. Запрещено использовать any. Для необязательных пропсов используй опциональные поля. Если пропс может быть одним из нескольких типов — используй union. Добавь JSDoc к каждому пропсу.
Пример: компонент с пропсами size, variant, onClick. Модель создаст `type Size = 'sm'
| 'md' | 'lg'иtype Variant = 'primary' | 'secondary', а неstring`.
11. Рефакторинг пропсов для читаемости
Задача: убрать «пропс-бурение» и сделать API компонента понятным.
Промт:
Проанализируй пропсы компонента ниже. Предложи рефакторинг: сгруппируй связанные пропсы в объекты, убери лишние, переименуй неочевидные. Не меняй поведение. Покажи до и после.
Пример: пропсы userName, userAge, userAvatar → user={{ name, age, avatar }}. Модель также может предложить использовать children вместо content.
12. Генерация prop-types для JS-проектов
Задача: добавить проверку типов в проекте без TypeScript.
Промт:
Сгенерируй propTypes для компонента ниже. Используй PropTypes из пакета prop-types. Для необязательных — .isRequired не ставить. Для массивов и объектов укажи shape, если структура известна.
Пример: компонент списка — items: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.string.isRequired })).
Промты для оптимизации и архитектуры
13. Выбор между useMemo и useCallback
Задача: не гадать, какой хук применить.
Промт:
У меня есть функция/значение [описание]. Объясни, нужно ли оборачивать его в useMemo, useCallback или оставить как есть. Учти: тип значения (функция, объект, массив), передаётся ли оно в дочерние компоненты, используется ли в зависимостях других хуков. Дай рекомендацию с обоснованием.
Пример: вы передаёте колбэк в React.memo-компонент — модель скажет, что нужен useCallback, иначе мемоизация бесполезна.
14. Архитектура состояния: Context vs useState
Задача: понять, когда поднимать состояние, а когда использовать контекст.
Промт:
У меня есть несколько компонентов, которые используют общие данные [описание]. Предложи архитектуру состояния: где хранить (локально, в родителе, в Context, во внешнем сторе). Объясни trade-off каждого варианта для моего случая. Учти частоту обновлений и количество потребителей.
Пример: тема оформления — Context; данные формы — локально; кэш API — React Query (внешний стор). Модель даст сравнение.
Как использовать эти промты
Все промты работают по одному принципу: вы задаёте ограничения, которые отсекают «плохие» паттерны из обучающих данных. Чем конкретнее запрет, тем лучше результат. Если модель всё равно генерирует useEffect для производного состояния — добавьте в промт фразу «если предлагаешь useEffect, обоснуй, почему без него нельзя».
Помните: LLM не запускает код. Ответственность за проверку логики и производительности лежит на вас. Используйте эти промты как ускоритель, а не как замену ревью. Больше практических приёмов для работы с LLM в разработке ищите в нашем блоге — например, в статье LLM как тимлид.