Next.js 15: Partial Prerendering с React 19 useActionState для динамических форм
-

Зацените, как в Next.js 15 Partial Prerendering (PPR) сочетается с useActionState из React 19 для динамических форм. Это киллер-фича для мгновенной валидации без полной перезагрузки страницы. Теперь статическая оболочка страницы летает, а формы обновляются на лету - DX на новом уровне.
PPR решает боль: раньше один динамический кусок кидал всю страницу в SSR, убивая производительность. С флагами experimental_ppr и Suspense вы гранулярно контролируете, что статично, а что стримится. А useActionState добавляет реактивный стейт для форм с серверными экшнами - валидация мгновенная, без лишних запросов. Идеально для дашбордов, корзин, профилей.
Под капотом PPR: статическая оболочка + динамические дыры
PPR в Next.js 15 делит рендер на статическую shell и динамические холы через Suspense. На билде генерится статический HTML с fallback’ами, а при запросе стримятся только нужные части - cookies, headers или query не ломают весь маршрут. Это как ISR + SSR в одном флаконе, но умнее: граница Suspense определяет, где динамика.
На первый взгляд кажется круто, но есть нюанс - пока экспериментально, не для продакшена на больших проектах. Подключается в next.config.js через experimental.ppr: ‘incremental’, плюс export const experimental_ppr = true в page.tsx. Next.js автоматически prerender’ит shell, а fallback’и (скелетоны, лоадеры) заменяются динамикой в том же HTTP-запросе. Web Vitals взлетают: LCP быстрее, FID нулевой.
Вот базовый сетап:
- next.config.js: добавьте
experimental: { ppr: 'incremental' }- включает инкрементальный PPR. - page.tsx:
export const experimental_ppr = true- активирует для маршрута и детей. - Suspense wrapper: оберните динамику, типа
<Suspense fallback={<Skeleton />}><DynamicForm /></Suspense>- shell статичен, дыра стримится. - Динамические триггеры: cookies(), searchParams() внутри Suspense - не крашат статическую часть.
Сравнение рендера Без PPR С PPR Статическая часть Нет Shell на билде Динамика Вся страница SSR Только в Suspense TTFB 200-500ms <100ms ISR совместимость Частично Полная useActionState в React 19: реактивные формы без костылей
useActionState - новый хук React 19 для серверных экшенов в формах. Он возвращает [state, action, isPending] - стейт обновляется автоматически после submit, без useState + useTransition. Идеально с PPR: форма в динамической дыре, валидация серверная, UI реактивный. Никакого бойлерплейта с ручным стейтом или эффектами.
Под капотом action - async функция, которая мутирует данные на сервере (DB, API), возвращает ошибку или успех. Хук трекает pending, обновляет state оптимистично. В Next.js 15 это рендерится в RSC (React Server Components), стримится в PPR-дыру. Мгновенная валидация: ошибки показываются сразу, без фулл-рилоада. Круто для сложных форм - рег, логин, корзина.
Короткий пример на TypeScript:
import { useActionState } from 'react'; async function loginAction(prevState: any, formData: FormData) { const email = formData.get('email'); // серверная валидация if (!email) return { error: 'Email обязателен' }; // API call return { success: true }; } export default function LoginForm() { const [state, submitAction, pending] = useActionState(loginAction, null); return ( <form action={submitAction}> <input name="email" /> {state?.error && <p>{state.error}</p>} <button disabled={pending}>Войти</button> </form> ); }- prevState: кумулятивные ошибки, не теряются при повторном сабмите.
- isPending: блокирует UI, показывает спиннер - UX на уровне.
- Серверный рендер: action выполняется на сервере, стейт стримится клиенту.
- TypeScript: типизуйте state как
LoginState | nullдля автокомплита.
Комбо PPR + useActionState: динамические формы в продакшен-стиле
Оборачиваем форму в Suspense внутри PPR-страницы: статический хедер/нейв, динамическая форма стримится. useActionState внутри - submit бьет сервер, state обновляется в дыре, без гидрации всего. Валидация мгновенная: поле подсвечивается, ошибки inline. Оптимизация Web Vitals: CLS минимальный, благодаря скелетонам.
Это просто боль решается: раньше формы лагали из-за полного SSR. Теперь гранулярно - шапка кэшируется, форма реактивна. Нюанс: в client-nav пока не стримит (soon), но для initial load огонь. Пример - дашборд с поиском: query в searchParams триггерит динамику, но только в таблице.
Полный пример страницы:
// app/dashboard/page.tsx export const experimental_ppr = true; import { Suspense } from 'react'; import LoginForm from './LoginForm'; export default function Dashboard() { return ( <div> <h1>Дашборд</h1> {/* статично */} <Suspense fallback={<div>Загрузка формы...</div>}> <LoginForm /> </Suspense> </div> ); }Преимущества комбо Описание Мгновенная валидация State обновляется в реал-тайм Core Web Vitals Shell + стриминг = топ метрики DX Меньше хуков, чистый код Масштаб Работает с ISR, не ломается Фичи, которые меняют правила игры
PPR с useActionState - это шаг к default-рендеру будущего: стат по умолчанию, динамика по необходимости. Осталось доработать client-side стриминг и full-prod readiness, но уже сейчас оптимизирует бандл и TTI. Подумать стоит над миграцией legacy-SSR чанков в Suspense - там пушка по перформансу. А вы уже тестите в пати-проектах?
- next.config.js: добавьте
Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.
Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.
С вашими комментариями этот пост мог бы стать ещё лучше 💗
Зарегистрироваться Войти© 2024 - 2026 ExLends, Inc. Все права защищены.