15 промтов для создания React/Next.js приложений: от компонентов до оптимизации

Введение

Разработка на React и Next.js — это не только написание кода, но и постоянное взаимодействие с документацией, поиск готовых решений и генерация boilerplate. С ростом популярности AI-ассистентов (ChatGPT, Claude, Copilot) умение формулировать правильные промты стало таким же важным навыком, как знание JSX или хуков. По данным опроса Stack Overflow за 2025 год, более 70% разработчиков используют AI-инструменты для генерации кода, но лишь каждый третий получает качественный результат — проблема чаще всего в неконкретных промтах.

В этой статье я собрал 15 проверенных промтов (базовые, продвинутые и экспертные), которые помогут вам ускорить разработку React/Next.js приложений: от простых компонентов до сложных страниц с SSR и оптимизацией. Каждый промт сопровождается примером результата и рекомендациями по настройке. Статья написана для разработчиков уровня Junior+ и Middle, которые хотят использовать AI как инструмент, а не как чёрный ящик.

Категория 1: Базовые промты (5 шт.)

1. Генерация функционального компонента с TypeScript

Задача: Быстро создать компонент с типизацией пропсов.

Промт:

Сгенерируй React функциональный компонент на TypeScript, который принимает props: { title: string, description?: string, onClick: () => void }. Компонент должен отображать заголовок (h2), описание (если есть) и кнопку. Используй стили через CSS-in-JS (styled-components или inline styles).

Пример результата:

import React from 'react';

interface CardProps {
  title: string;
  description?: string;
  onClick: () => void;
}

const Card: React.FC<CardProps> = ({ title, description, onClick }) => {
  return (
    <div style={{ border: '1px solid #ccc', padding: '16px', borderRadius: '8px' }}>
      <h2>{title}</h2>
      {description && <p>{description}</p>}
      <button onClick={onClick}>Click me</button>
    </div>
  );
};

export default Card;

Совет: Уточняйте в промте, используете ли вы TypeScript, иначе AI может сгенерировать JS-код без типов.

2. Создание формы с валидацией (React Hook Form)

Задача: Получить готовую форму с регистрацией полей и базовой валидацией.

Промт:

Напиши React компонент формы регистрации с полями: email (required, email format), password (required, minLength 6), confirmPassword (must match password). Используй библиотеку react-hook-form и yup для схемы валидации. При успешной отправке выводи alert с сообщением.

Пример результата (сокращённо):

import React from 'react';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';

const schema = yup.object().shape({
  email: yup.string().email('Invalid email').required('Email is required'),
  password: yup.string().min(6, 'Min 6 characters').required(),
  confirmPassword: yup.string().oneOf([yup.ref('password')], 'Passwords must match').required(),
});

interface FormData {
  email: string;
  password: string;
  confirmPassword: string;
}

const RegistrationForm: React.FC = () => {
  const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    resolver: yupResolver(schema),
  });

  const onSubmit = (data: FormData) => {
    alert(`Registered with email: ${data.email}`);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label>Email</label>
        <input {...register('email')} />
        {errors.email && <p>{errors.email.message}</p>}
      </div>
      <div>
        <label>Password</label>
        <input type="password" {...register('password')} />
        {errors.password && <p>{errors.password.message}</p>}
      </div>
      <div>
        <label>Confirm Password</label>
        <input type="password" {...register('confirmPassword')} />
        {errors.confirmPassword && <p>{errors.confirmPassword.message}</p>}
      </div>
      <button type="submit">Register</button>
    </form>
  );
};

export default RegistrationForm;

3. Компонент списка с фильтрацией и поиском

Задача: Сгенерировать компонент, который рендерит массив данных с возможностью фильтрации по тексту.

Промт:

Создай React компонент, который принимает массив объектов { id: number, name: string, category: string }. Реализуй поиск по name (input) и фильтрацию по category (select с опциями All, Category1, Category2). Отображай отфильтрованный список в виде карточек. Используй useState.

Пример результата (ключевая часть):

const [search, setSearch] = useState('');
const [category, setCategory] = useState('All');

const filtered = data.filter(item => {
  const nameMatch = item.name.toLowerCase().includes(search.toLowerCase());
  const catMatch = category === 'All' || item.category === category;
  return nameMatch && catMatch;
});

4. Хук useFetch для получения данных

Задача: Получить кастомный хук для работы с API.

Промт:

Напиши React хук useFetch, который принимает URL и возвращает { data, loading, error }. Используй useEffect и fetch API. Добавь поддержку отмены запроса через AbortController.

Пример результата:

import { useState, useEffect } from 'react';

function useFetch<T>(url: string) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const controller = new AbortController();
    setLoading(true);
    fetch(url, { signal: controller.signal })
      .then(res => res.json())
      .then(setData)
      .catch(err => {
        if (err.name !== 'AbortError') setError(err.message);
      })
      .finally(() => setLoading(false));
    return () => controller.abort();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

5. Модальное окно с анимацией

Задача: Создать переиспользуемый компонент модального окна с плавным появлением.

Промт:

Создай React компонент Modal с пропсами: isOpen, onClose, children. Реализуй анимацию появления/исчезания через CSS transition (opacity, transform). Добавь закрытие по клику на оверлей и по Escape. Используй React Portal.

Пример результата (структура):

import React, { useEffect } from 'react';
import ReactDOM from 'react-dom';

const Modal: React.FC<{ isOpen: boolean; onClose: () => void; children: React.ReactNode }> = ({ isOpen, onClose, children }) => {
  useEffect(() => {
    const handleEsc = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };
    if (isOpen) document.addEventListener('keydown', handleEsc);
    return () => document.removeEventListener('keydown', handleEsc);
  }, [isOpen, onClose]);

  if (!isOpen) return null;

  return ReactDOM.createPortal(
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal-content" onClick={e => e.stopPropagation()}>
        {children}
      </div>
    </div>,
    document.body
  );
};

Категория 2: Продвинутые промты (5 шт.)

6. Генерация Next.js страницы с SSR и getServerSideProps

Задача: Создать страницу с серверным рендерингом и получением данных из API.

Промт:

Напиши Next.js страницу /products, которая использует getServerSideProps для получения списка продуктов из внешнего API (например, https://fakestoreapi.com/products). Отобрази продукты в виде сетки карточек с изображением, названием и ценой. Добавь обработку ошибок и fallback UI.

Пример результата:

import { GetServerSideProps } from 'next';
import React from 'react';

interface Product {
  id: number;
  title: string;
  price: number;
  image: string;
}

interface Props {
  products: Product[];
  error?: string;
}

const ProductsPage: React.FC<Props> = ({ products, error }) => {
  if (error) return <div>Error: {error}</div>;
  return (
    <div className="grid grid-cols-3 gap-4">
      {products.map(p => (
        <div key={p.id}>
          <img src={p.image} alt={p.title} width={200} height={200} />
          <h3>{p.title}</h3>
          <p>${p.price}</p>
        </div>
      ))}
    </div>
  );
};

export const getServerSideProps: GetServerSideProps = async () => {
  try {
    const res = await fetch('https://fakestoreapi.com/products');
    const products = await res.json();
    return { props: { products } };
  } catch (err) {
    return { props: { products: [], error: 'Failed to fetch' } };
  }
};

export default ProductsPage;

7. Динамический маршрут Next.js с getStaticPaths

Задача: Создать статическую страницу для каждого продукта с генерацией путей.

Промт:

Создай Next.js страницу /products/[id] с getStaticPaths и getStaticProps. Используй тот же API фейковых товаров. Страница должна показывать детальную информацию о продукте (название, цена, описание, изображение). Если продукт не найден  верни 404.

Пример результата (часть):

export const getStaticPaths: GetStaticPaths = async () => {
  const res = await fetch('https://fakestoreapi.com/products');
  const products = await res.json();
  const paths = products.map((p: Product) => ({ params: { id: p.id.toString() } }));
  return { paths, fallback: false };
};

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const res = await fetch(`https://fakestoreapi.com/products/${params.id}`);
  if (!res.ok) return { notFound: true };
  const product = await res.json();
  return { props: { product } };
};

8. Компонент с оптимизацией через React.memo и useMemo

Задача: Улучшить производительность компонента списка.

Промт:

Напиши React компонент ExpensiveList, который принимает массив items (с полями id, value) и отображает их в виде списка. Используй React.memo для обёртки компонента, useMemo для сортировки items по value, useCallback для функции-обработчика клика. Покажи разницу производительности с комментариями.

Пример результата:

const ExpensiveList: React.FC<{ items: Item[] }> = React.memo(({ items }) => {
  const sorted = useMemo(() => [...items].sort((a, b) => a.value - b.value), [items]);
  const handleClick = useCallback((id: number) => {
    console.log('Clicked', id);
  }, []);

  return (
    <ul>
      {sorted.map(item => (
        <li key={item.id} onClick={() => handleClick(item.id)}>{item.value}</li>
      ))}
    </ul>
  );
});

9. useContext + useReducer для глобального состояния

Задача: Реализовать управление корзиной через Context API.

Промт:

Создай контекст CartContext с провайдером, использующим useReducer. Реализуй действия: ADD_ITEM, REMOVE_ITEM, CLEAR. Каждый item имеет id, name, price, quantity. Напиши кастомный хук useCart для доступа к контексту.

Пример результата (редьюсер):

type Action = 
  | { type: 'ADD_ITEM'; payload: CartItem }
  | { type: 'REMOVE_ITEM'; payload: number }
  | { type: 'CLEAR' };

const cartReducer = (state: CartItem[], action: Action): CartItem[] => {
  switch (action.type) {
    case 'ADD_ITEM':
      const existing = state.find(i => i.id === action.payload.id);
      if (existing) {
        return state.map(i => i.id === action.payload.id ? { ...i, quantity: i.quantity + 1 } : i);
      }
      return [...state, action.payload];
    case 'REMOVE_ITEM':
      return state.filter(i => i.id !== action.payload);
    case 'CLEAR':
      return [];
    default:
      return state;
  }
};

10. Next.js API Route с валидацией

Задача: Создать эндпоинт для регистрации пользователя.

Промт:

Напиши Next.js API route в pages/api/register.ts (или app/api/register/route.ts для App Router). Принимает POST запрос с email и password. Валидируй поля (email формат, password min 6). Если валидация не пройдена  верни 400. В случае успеха  верни 201 и сообщение. Используй Zod для схемы.

Пример результата (App Router):

import { NextResponse } from 'next/server';
import { z } from 'zod';

const schema = z.object({
  email: z.string().email(),
  password: z.string().min(6),
});

export async function POST(request: Request) {
  try {
    const body = await request.json();
    const parsed = schema.parse(body);
    // Здесь логика сохранения в БД
    return NextResponse.json({ message: 'User created' }, { status: 201 });
  } catch (error) {
    if (error instanceof z.ZodError) {
      return NextResponse.json({ errors: error.errors }, { status: 400 });
    }
    return NextResponse.json({ message: 'Internal error' }, { status: 500 });
  }
}

Категория 3: Экспертные промты (5 шт.)

11. Компонент с Suspense и React.lazy для ленивой загрузки

Задача: Реализовать lazy loading для тяжёлого компонента с fallback.

Промт:

Создай компонент DashboardPage, который импортирует тяжёлый компонент Chart через React.lazy и оборачивает его в Suspense с fallback (скелетон). Используй ErrorBoundary на случай ошибки загрузки чанка. Покажи полный пример с обработкой ошибок.

Пример результата (структура):

import React, { Suspense, lazy } from 'react';
import ErrorBoundary from './ErrorBoundary';

const Chart = lazy(() => import('./Chart'));

const DashboardPage: React.FC = () => {
  return (
    <ErrorBoundary fallback={<div>Failed to load chart</div>}>
      <Suspense fallback={<div className="skeleton" style={{ height: 400 }} />}>
        <Chart />
      </Suspense>
    </ErrorBoundary>
  );
};

12. Next.js Middleware для аутентификации

Задача: Написать middleware, который проверяет JWT токен и перенаправляет на логин.

Промт:

Создай Next.js middleware для защиты маршрутов /dashboard и /profile. Middleware должен проверять наличие cookie 'token' и его валидность (имитируй проверку JWT). Если токен отсутствует или недействителен  редирект на /login. Используй NextResponse.rewrite.

Пример результата:

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

const protectedPaths = ['/dashboard', '/profile'];

export function middleware(request: NextRequest) {
  const token = request.cookies.get('token')?.value;
  const { pathname } = request.nextUrl;

  if (protectedPaths.some(p => pathname.startsWith(p))) {
    if (!token) {
      return NextResponse.redirect(new URL('/login', request.url));
    }
    // Здесь можно добавить проверку JWT
  }

  return NextResponse.next();
}

export const config = {
  matcher: ['/dashboard/:path*', '/profile/:path*'],
};

13. Оптимизация рендеринга с useTransition и useDeferredValue

Задача: Сделать плавный UI при фильтрации большого списка.

Промт:

Создай компонент SearchableList, который отображает 10000 элементов. Используй useDeferredValue для отложенного обновления списка и useTransition для пометки обновления как низкоприоритетного. Покажи индикатор загрузки во время фильтрации.

Пример результата (ключевая часть):

const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
const [isPending, startTransition] = useTransition();

const filtered = useMemo(() => {
  return largeList.filter(item => item.name.includes(deferredQuery));
}, [deferredQuery]);

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  startTransition(() => setQuery(e.target.value));
};

14. Кастомный хук для работы с localStorage с синхронизацией

Задача: Создать хук, который сохраняет состояние в localStorage и синхронизируется между вкладками.

Промт:

Напиши хук useLocalStorage, который принимает ключ и начальное значение. Хук должен: 1) читать из localStorage при монтировании, 2) обновлять localStorage при изменении, 3) слушать событие storage для синхронизации между вкладками. Используй JSON.parse/stringify.

Пример результата:

function useLocalStorage<T>(key: string, initialValue: T) {
  const [storedValue, setStoredValue] = useState<T>(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch {
      return initialValue;
    }
  });

  useEffect(() => {
    const handleStorage = (e: StorageEvent) => {
      if (e.key === key) {
        setStoredValue(e.newValue ? JSON.parse(e.newValue) : initialValue);
      }
    };
    window.addEventListener('storage', handleStorage);
    return () => window.removeEventListener('storage', handleStorage);
  }, [key, initialValue]);

  const setValue = (value: T | ((val: T) => T)) => {
    const valueToStore = value instanceof Function ? value(storedValue) : value;
    setStoredValue(valueToStore);
    window.localStorage.setItem(key, JSON.stringify(valueToStore));
  };

  return [storedValue, setValue] as const;
}

15. Next.js App Router — параллельные маршруты и интерсепшены

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

Промт:

Используя Next.js App Router, настрой параллельный маршрут для модального окна. Страница /products показывает список продуктов. При клике на продукт открывается модальное окно с деталями (роут /products/[id] отображается в модалке). Используй @modal параллельный маршрут и интерсепшн роутов.

Пример результата (структура папок):

app/
  page.tsx
  layout.tsx
  products/
    page.tsx
    [id]/
      page.tsx
  @modal/
    (.)products/[id]/
      page.tsx
  default.tsx

Пример layout.tsx:

export default function RootLayout({ children, modal }: { children: React.ReactNode; modal: React.ReactNode }) {
  return (
    <html>
      <body>
        {children}
        {modal}
      </body>
    </html>
  );
}

Таблица сравнения промтов по сложности и применению

Категория Уровень Пример задачи Результат Инструменты
Базовые Junior Компонент с пропсами Функциональный компонент React, TypeScript
Базовые Junior Форма с валидацией Рабочая форма react-hook-form, yup
Продвинутые Middle SSR страница Страница с getServerSideProps Next.js, fetch
Продвинутые Middle Динамический маршрут Статические страницы getStaticPaths
Экспертные Senior Middleware аутентификации Защита маршрутов Next.js Middleware
Экспертные Senior Параллельные маршруты Модальное окно App Router

Заключение

Правильно составленный промт — это половина успеха при работе с AI-ассистентами. Надеюсь, эта подборка поможет вам быстрее создавать React и Next.js компоненты, избегая типичных ошибок: неполных пропсов, отсутствия типизации или неправильной архитектуры. Помните, что AI — это инструмент, а не замена пониманию. Всегда проверяйте сгенерированный код, тестируйте его и адаптируйте под свой проект.

Если вы хотите углубиться в тему и научиться интегрировать AI в свой рабочий процесс, обратите внимание на курсы, которые обучают практическим навыкам работы с современными фреймворками. ASI Biont поддерживает подключение к различным API для автоматизации разработки — подробнее на asibiont.com/courses.

Пишите в комментариях, какие промты вы используете чаще всего, и делитесь своими находками. Удачного кодинга!

← Все статьи

Комментарии