New skills: - next-best-practices: Next.js 15+ RSC, async patterns, self-hosting (vercel-labs) - better-auth-best-practices: Official Better-Auth with Drizzle adapter (better-auth) - verification-before-completion: Evidence-based completion claims (obra/superpowers) - shadcn-ui: Component patterns with Tailwind v4 adaptation note (developer-kit) - writing-skills: TDD methodology for skill authoring (obra/superpowers) README reorganized by category with Mosaic Stack alignment section. Total: 9 skills (4 existing + 5 new). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
88 lines
1.6 KiB
Markdown
88 lines
1.6 KiB
Markdown
# Async Patterns
|
|
|
|
In Next.js 15+, `params`, `searchParams`, `cookies()`, and `headers()` are asynchronous.
|
|
|
|
## Async Params and SearchParams
|
|
|
|
Always type them as `Promise<...>` and await them.
|
|
|
|
### Pages and Layouts
|
|
|
|
```tsx
|
|
type Props = { params: Promise<{ slug: string }> }
|
|
|
|
export default async function Page({ params }: Props) {
|
|
const { slug } = await params
|
|
}
|
|
```
|
|
|
|
### Route Handlers
|
|
|
|
```tsx
|
|
export async function GET(
|
|
request: Request,
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
) {
|
|
const { id } = await params
|
|
}
|
|
```
|
|
|
|
### SearchParams
|
|
|
|
```tsx
|
|
type Props = {
|
|
params: Promise<{ slug: string }>
|
|
searchParams: Promise<{ query?: string }>
|
|
}
|
|
|
|
export default async function Page({ params, searchParams }: Props) {
|
|
const { slug } = await params
|
|
const { query } = await searchParams
|
|
}
|
|
```
|
|
|
|
### Synchronous Components
|
|
|
|
Use `React.use()` for non-async components:
|
|
|
|
```tsx
|
|
import { use } from 'react'
|
|
|
|
type Props = { params: Promise<{ slug: string }> }
|
|
|
|
export default function Page({ params }: Props) {
|
|
const { slug } = use(params)
|
|
}
|
|
```
|
|
|
|
### generateMetadata
|
|
|
|
```tsx
|
|
type Props = { params: Promise<{ slug: string }> }
|
|
|
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|
const { slug } = await params
|
|
return { title: slug }
|
|
}
|
|
```
|
|
|
|
## Async Cookies and Headers
|
|
|
|
```tsx
|
|
import { cookies, headers } from 'next/headers'
|
|
|
|
export default async function Page() {
|
|
const cookieStore = await cookies()
|
|
const headersList = await headers()
|
|
|
|
const theme = cookieStore.get('theme')
|
|
const userAgent = headersList.get('user-agent')
|
|
}
|
|
```
|
|
|
|
## Migration Codemod
|
|
|
|
```bash
|
|
npx @next/codemod@latest next-async-request-api .
|
|
```
|