ae39e45460
NOVAS SKILLS: - next-best-practices v0.1.0 (CLEAN) — Next.js App Router, RSC, caching, data - nextjs-patterns v1.0.0 (CLEAN) — Next.js 15: Server Actions, route handlers - vite v1.0.0 (CLEAN) — env vars, aliases, proxy, CJS compat - uncle-bob v1.0.0 (CLEAN) — Clean Code, SOLID, Clean Architecture - clean-code-review v1.0.0 (CLEAN) — naming, guard clauses, anti-patterns, refactoring - vue v1.0.0 (CLEAN) — Vue framework - vue-composition-api-best-practices v1.0.0 (CLEAN) — composables, Pinia, reactivity BIBLIOTECA INTELIGENTE libs/ (10 dominios, 11 arquivos): - typescript/ — TS safe + generics gotchas - react/ — Next.js App Router + Vite config - vue/ — Composition API + Pinia - linux/ — System diagnostic cheatsheet - database/ — PostgreSQL + MySQL patterns - browser/ — Chromium CLI + E2E testing - security/ — SAST audit (OWASP Top 10) - best-practices/ — Clean Code + SOLID + Clean Architecture - deploy/ — Docker multi-stack + OpenClaw ops - + INDEX.md como guia de navegacao .learnings/ — LRN-20260519-003 criado (biblioteca compartilhada)
82 lines
2.3 KiB
Markdown
82 lines
2.3 KiB
Markdown
# Next.js 15 Caching Deep Dive
|
|
|
|
## The Four Caching Layers
|
|
|
|
### 1. Request Memoization (in-memory, per request)
|
|
Automatically deduplicates identical `fetch()` calls within a single render tree.
|
|
|
|
```tsx
|
|
// Both components call fetchUser(id) — only ONE network request is made
|
|
async function Avatar({ id }) { const u = await fetchUser(id); return <img src={u.avatar} /> }
|
|
async function Name({ id }) { const u = await fetchUser(id); return <span>{u.name}</span> }
|
|
```
|
|
|
|
### 2. Data Cache (persistent, cross-request)
|
|
`fetch()` responses are stored on the server and reused across requests and deployments.
|
|
|
|
```tsx
|
|
// Static — cached indefinitely
|
|
fetch(url)
|
|
fetch(url, { cache: "force-cache" })
|
|
|
|
// Time-based revalidation (ISR)
|
|
fetch(url, { next: { revalidate: 3600 } }) // revalidate every hour
|
|
|
|
// Always fresh — no caching
|
|
fetch(url, { cache: "no-store" })
|
|
fetch(url, { next: { revalidate: 0 } })
|
|
```
|
|
|
|
### 3. Full Route Cache (build-time static rendering)
|
|
Pages rendered at build time are stored as static HTML+RSC payload.
|
|
|
|
```tsx
|
|
// Force dynamic rendering for this route
|
|
export const dynamic = "force-dynamic"
|
|
|
|
// Custom revalidation period for the whole route
|
|
export const revalidate = 60
|
|
```
|
|
|
|
### 4. Router Cache (client-side, per session)
|
|
Browser caches RSC payloads for instant back/forward navigation.
|
|
- Static routes: cached for 5 minutes
|
|
- Dynamic routes: cached for 30 seconds
|
|
|
|
## On-Demand Revalidation
|
|
|
|
```ts
|
|
// Revalidate by path
|
|
import { revalidatePath } from "next/cache"
|
|
revalidatePath("/blog")
|
|
revalidatePath("/blog/[slug]", "page")
|
|
|
|
// Revalidate by cache tag
|
|
import { revalidateTag } from "next/cache"
|
|
revalidateTag("posts")
|
|
|
|
// Tagging fetches
|
|
fetch(url, { next: { tags: ["posts"] } })
|
|
```
|
|
|
|
## unstable_cache for Non-Fetch Data
|
|
|
|
```ts
|
|
import { unstable_cache } from "next/cache"
|
|
|
|
const getCachedUser = unstable_cache(
|
|
async (id: string) => db.user.findUnique({ where: { id } }),
|
|
["user"],
|
|
{ revalidate: 300, tags: ["users"] }
|
|
)
|
|
```
|
|
|
|
## Common Pitfalls
|
|
|
|
| Mistake | Fix |
|
|
|---------|-----|
|
|
| Using `fetch` inside `useEffect` | Move to Server Component or use React Query |
|
|
| Forgetting `revalidatePath` after mutations | Call in Server Action after every write |
|
|
| Over-caching user-specific data | Add `cache: "no-store"` or check `cookies()`/`headers()` |
|
|
| Sequential awaits | Use `Promise.all()` for parallel fetching |
|