Capítulo 25 de 456
Com cacheComponents: true, leitura de sessão só pode acontecer em request time (não entra no static shell), então UI autenticada sempre fica atrás de <Suspense>. use cache: private é o mecanismo para cachear no navegador dados derivados de cookies()/headers() sem nunca persistir no servidor.
use cache: private: diretiva que lê cookies(), headers() e searchParams diretamente; mantém o resultado só no navegador, nunca no servidor. Usa o default cache profile (stale de 5min) se cacheLife não for setado.getCurrentUser()), retornando um objeto estreito ({id, name}), nunca a sessão crua.userId da sessão e passar para uma função use cache (plain) ou use cache: remote normal, cacheada no servidor e com cacheTag.export const instant = false: opt-out de validação de instant navigation, permite rota continuar bloqueando no servidor durante migração incremental para Cache Components.getCurrentUser() uma vez dentro do boundary, passar por Context Provider, e consumir com use() em Client Components, evitando reler a sessão em cada componente.// lib/auth.ts — DAL, cacheia a leitura de sessão só no browser
export async function getCurrentUser(): Promise<User> {
'use cache: private'
const { userId } = await getSession()
if (!userId) redirect('/login')
const user = await findUserById(userId)
if (!user) redirect('/login')
return { id: user.id, name: user.name }
}
redirect() interrompe o render (não é cacheado), só o User resolvido é.// app/page.tsx — UI autenticada atrás de Suspense, resto prerenderiza
export default function Page() {
return (
<main>
<Announcements /> {/* 'use cache', entra no static shell */}
<Suspense fallback={<p>Loading your dashboard…</p>}>
<Dashboard /> {/* lê sessão, streama */}
</Suspense>
</main>
)
}
// lib/data.ts — cache de dado derivado, keyed por userId, invalidável por tag
async function getNotesByUserId(userId: string) {
'use cache'
cacheTag(`notes:${userId}`)
cacheLife('minutes')
return db.query.notes.findMany({ where: (n, { eq }) => eq(n.userId, userId) })
}
getNotesByUserId não-exportada evita que um caller passe outro userId arbitrário; segurança vem de resolver o usuário dentro do getter exportado.cookies()/headers() dentro de use cache plain: lança erro em build. Ler fora e passar valor, ou usar use cache: private.cacheTag são armazenados em texto plano (não hasheados). Usar identificador estável (ex. userId), nunca token/email/senha.{children} inteiro atrás do request; empurrar a leitura para um componente dentro de um boundary.<Suspense> e usa use cache: private para ganhar lifetime de cache sem tocar servidor.cacheTag/updateTag), extraia um id estável e passe para use cache plain ou use cache: remote.export const instant = false é o mecanismo de migração incremental, não a solução final.stale >= 30s; rotas que dependem de URL precisam de <Link prefetch={true}> + Partial Prefetching.use cache: private complementa para dados server-side.