NAME
nextjs-16-cache-components — Next.js 16, компоненты кэша и компилятор React: что действительно меняется
SYNOPSIS
cat nextjs-16-cache-components.md
DESCRIPTION
В течение многих лет одним из самых раздражающих вопросов в Next.js был: «Эта страница статичная или динамическая?». Это кажется простым вопросом, пока вы не добавите вызов cookies(), fetch с различными опциями, клиента базы данных, CMS, корзины покупок или фрагмента пользовательского контента.
Next.js 16 интересен тем, что пытается сделать этот разговор менее загадочным. Это не устраняет сложность, но меняет ментальную модель: маршруты по умолчанию являются динамическими, кэш объявляет себя там, где это необходимо, а Suspense становится естественным способом составления быстрых оболочек из частей, которые остаются свежими.
Особенность, которую нужно понять, — это компоненты кэша. Стабильный Turbopack, React Compiler, proxy.ts и новые API-интерфейсы инвалидации важны, но они вращаются вокруг одной и той же проблемы: создание быстрых приложений без необходимости угадывать, что за кулисами решила платформа.
Потому что это важно
В реальном приложении есть не просто «статические страницы» и «динамические страницы». У вас есть разные вещи с разными потребностями.
Список продуктов может меняться несколько раз в день. Цена может меняться чаще. Наличие должно быть почти живое. Имя пользователя является личным. Обзоры можно транслировать. Боковая панель может быть стабильной. Тележки нет.
Если вы относитесь ко всему как к единому целому, вы всегда попадаете в одну из двух крайностей:
- агрессивное кэширование и риск увидеть старые данные;
- динамический рендеринг везде и производительность хуже, чем нужно.
Компоненты кэша служат именно для того, чтобы избежать этого ошибочного выбора.
Модель на практике
С помощью cacheComponents: true вы можете объявить, что кэшируется, используя "use cache". Затем вы можете связать продолжительность и теги с cacheLife() и cacheTag(). Динамические части остаются динамическими и могут быть изолированы с помощью Suspense.
Установка небольшая:
// next.config.ts import type { NextConfig } from 'next'; const nextConfig: NextConfig = { cacheComponents: true, }; export default nextConfig;
Большие изменения не в конфигурации. Дело в том, как вы начинаете писать компоненты.
// app/products/[slug]/page.tsx import { Suspense } from 'react'; import { cacheLife, cacheTag } from 'next/cache'; async function getProduct(slug: string) { 'use cache'; cacheLife('hours'); cacheTag(`product:${slug}`); return db.product.findUnique({ where: { slug } }); } async function ProductDetails({ slug }: { slug: string }) { const product = await getProduct(slug); return ( <section> <h1>{product.name}</h1> <p>{product.description}</p> </section> ); } async function LiveInventory({ slug }: { slug: string }) { const inventory = await db.inventory.findFirst({ where: { slug } }); return <p>{inventory.quantity} pezzi disponibili</p>; } export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params; return ( <> <ProductDetails slug={slug} /> <Suspense fallback={<p>Controllo disponibilità...</p>}> <LiveInventory slug={slug} /> </Suspense> </> ); }
Страница не обязательно должна быть полностью кэшированной или полностью динамической. Лист продукта может быть быстрым и многоразовым. Инвентарь может оставаться свежим. Пользователь видит что-то сразу, не дожидаясь самой медленной части.
use cache — исполняемая документация.
Что мне нравится в "use cache", так это то, что он заставляет вас явно выражать намерение. Когда читаешь функцию, сразу понимаешь, что кто-то решил: «эти данные можно использовать повторно».
Это особенно полезно, когда вы не используете fetch. Многие приложения считывают данные из Prisma, Drizzle, внутренних SDK, клиентов CMS или сервисных функций. В таких случаях старых рассуждений, основанных только на опциях fetch, было недостаточно.
Эмпирическое правило:
- содержимое кэша относительно стабильное;
- используйте детальные теги;
- оставляет динамические разрешения, сеансы, корзины, уведомления и состояния транзакций;
- поместите медленные части внутрь
Suspense; - измеряйте, прежде чем сказать: «Мы улучшили производительность».
Недействителен, не выбрасывая все
Кэш полезен только в том случае, если вы можете его точно обновить. Здесь становятся важными cacheTag, revalidateTag и updateTag.
Пример:
'use server'; import { updateTag } from 'next/cache'; export async function updateProductName(productId: string, name: string) { await db.product.update({ where: { id: productId }, data: { name }, }); updateTag(`product:${productId}`); }
Важная деталь – бирка. product:${productId} указывает точную границу. products сообщает об огромном ведре. Поначалу огромное ведро удобно; через несколько месяцев это становится причиной того, что вы аннулируете половину приложения, чтобы изменить название.
Стабильный турбопак: то, что вы слышите каждый день
Next.js 16 превращает Turbopack в центр разработки и сборки. Это не самая поэтичная особенность, но именно ее вы ощущаете во время работы: сервер запускается раньше, более быстрое обновление, сборки, которые перестают напоминать вынужденный перерыв на кофе.
Тем не менее, я бы не стал переносить кодовую базу, полную пользовательских плагинов, с закрытыми глазами. Я бы проверил:
- локальная сборка;
- нестандартный импорт;
- MDX, SVG и CSS;
- Остались плагины Webpack;
- критические страницы;
- различия во времени сборки.
Для новых проектов я бы начал со значения по умолчанию. Для зрелых я бы сделал размеренную миграцию.
React Compiler: убираем шум, а не мысли
React Compiler 1.0 стабилен, а Next.js 16 поддерживает его с помощью reactCompiler. Обещание состоит в том, чтобы сократить объем ручного запоминания: меньше memo, меньше useMemo, меньше useCallback, используемых «в целях безопасности».
// next.config.ts import type { NextConfig } from 'next'; const nextConfig: NextConfig = { reactCompiler: true, }; export default nextConfig;
Я бы не стал относиться к этому как к волшебной пыли. Компилятор помогает, когда код хорошо следует правилам React. Если компоненты имеют странные побочные эффекты, скрытые мутации или неправильно используемые хуки, это необходимо сначала исправить.
Здоровый способ попробовать:
- обновить
eslint-plugin-react-hooks; - фиксировать фактические нарушения;
- включить его на контролируемой территории;
- измерять время сборки и поведение;
- удаляйте ручное запоминание только тогда, когда оно больше не нужно.
Цель состоит не в том, чтобы стереть все useMemo. Цель — прекратить писать профилактическую мемоизацию, потому что мы боимся рендеринга.
proxy.ts и граница сети
Старый middleware.ts становится proxy.ts. Это изменение имени, но оно имеет смысл: этот файл находится на границе запроса, а не традиционное универсальное промежуточное программное обеспечение в стиле серверной части.
// proxy.ts import { NextRequest, NextResponse } from 'next/server'; export default function proxy(request: NextRequest) { const isLoggedIn = Boolean(request.cookies.get('session')); if (!isLoggedIn && request.nextUrl.pathname.startsWith('/dashboard')) { return NextResponse.redirect(new URL('/login', request.url)); } return NextResponse.next(); }
Правило здесь простое: пусть оно будет небольшим. Перенаправление, маршрутизация аутентификации, заголовки, существенные перезаписи. Если он начинает ощущаться как второй бэкэнд, возможно, он делает слишком много.
Как бы я на самом деле мигрировал
Я бы не стал включать все функции сразу. Я бы сделал это:
- Я обновляю Next, React и React DOM;
- Запускаю официальный кодмод;
- Я исправляю критические изменения в
params,searchParams,cookies(),headers()иdraftMode(); - Я переношу
middleware.tsнаproxy.ts; - Проверяю сборки и критические страницы;
- Я включаю компоненты кэша в разделе, где кеш в настоящее время создает проблемы;
- Я определяю соглашения для тегов и аннулирования;
- Я пробую React Compiler отдельно;
- сравнение показателей до и после.
Хорошая миграция — это не та миграция, которая использует все новые функции. Это делает поведение приложения более читабельным.
Что меняется в образе мышления
Самое полезное в Next.js 16 — это то, что он заставляет вас лучше называть намерения. Функция — это не просто «получить товар из базы данных». Это «получите товар, я могу его кэшировать часами, я аннулирую его с помощью этого тега». Компонент — это не просто «рендеринг страницы». Это «это быстрая оболочка, это личное, это идет в потоковом режиме».
На первый взгляд кажется, что работы больше. Тогда это становится формой спокойствия. Решения по производительности больше не скрыты в сочетании настроек по умолчанию, эвристики и племенной памяти. Они в коде.
Полезные источники
METADATA
- date: 2026-05-24
- reading: 6 min
- author: Filippo Spinella
- tags: Next.js, React, Frontend, Performance