Skip to main content

react-rsc

Use when working with React Server Components — choosing between Server and Client components, designing the server/client boundary, debugging hydration mismatches, fetching data on the server, using Server Actions, optimizing initial load, or migrating from a Pages Router or pure client-side React app to App Router + RSC.

Quellinformationen

Repository
Manavarya09/bullpen
Letzte Quellaktivität
4. Mai 2026 um 06:02
Erkannte Sprache von SKILL.md
Englisch
Sterne
10
Forks
1

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
react-rsc
description
Use when working with React Server Components — choosing between Server and Client components, designing the server/client boundary, debugging hydration mismatches, fetching data on the server, using Server Actions, optimizing initial load, or migrating from a Pages Router or pure client-side React app to App Router + RSC.
# React Server Components — pragmatic 2025 playbook This skill captures the production patterns that work in real codebases. It's prescriptive on purpose. Deviate only with a stated reason. ## When to use this skill - Picking between Server and Client component for a new piece of UI - Designing or moving the server/client boundary - Hitting a hydration mismatch - Fetching data — async/await in components, caching, revalidation - Building forms with Server Actions - Migrating Pages Router → App Router - Cutting JS bundle size on the critical path ## Iron law **Server is the default. `"use client"` is the exception.** If you can't articulate *why* a component must run on the client (it uses state, effects, browser APIs, or event handlers), it's a Server Component. This single discipline is responsible for 80% of the perf gap between RSC-savvy and RSC-naive codebases. ## The decision tree ``` Does it use useState, useEffect, useReducer, useContext (read), useRef, refs to DOM, event handlers, browser APIs (window, localStorage, etc.)? ├─ NO → Server Component (no directive) └─ YES → Client Component ("use client" at the TOP) └─ Push the boundary as far down the tree as possible. Server children of Client components are still server-rendered. ``` ## Patterns ### 1. Push `"use client"` to the leaf **Wrong:** ```tsx "use client"; // ❌ entire page is now client-only export default function Page() { return ( <div> <Header /> {/* could be server */} <ProductList /> {/* could be server */} <CartButton /> {/* needs client */} </div> ); } ``` **Right:** ```tsx // page.tsx — Server (no directive) export default function Page() { return ( <div> <Header /> <ProductList /> <CartButton /> {/* this one is "use client" inside its file */} </div> ); } ``` ### 2. Pass server data as props, not via useEffect **Wrong:** ```tsx "use client"; function ProductList() { const [data, setData] = useState(); useEffect(() => { fetch('/api/products').then(r => r.json()).then(setData); }, []); // double-fetch, layout shift, no SSR data } ``` **Right:** ```tsx // products/page.tsx — Server export default async function Page() { const products = await getProducts(); return <ProductList products={products} />; } ``` ### 3. Server Actions for forms — not API routes **Wrong:** dedicated `/api/contact` POST + client fetch + custom optimistic logic. **Right:** ```tsx // actions.ts "use server"; export async function sendMessage(prev: State, formData: FormData) { const parsed = Schema.parse(Object.fromEntries(formData)); await db.insert(parsed); revalidatePath('/inbox'); return { ok: true }; } // form.tsx — Client (only because of useFormState) "use client"; import { useFormState } from 'react-dom'; import { sendMessage } from './actions'; export function Form() { const [state, action] = useFormState(sendMessage, { ok: null }); return <form action={action}>...</form>; } ``` ### 4. Suspense + streaming for slow data ```tsx // page.tsx — Server export default function Page() { return ( <> <Header /> {/* ships immediately */} <Suspense fallback={<Skeleton />}> <SlowProducts /> {/* streams when ready */} </Suspense> </> ); } async function SlowProducts() { const products = await getProductsSlow(); // 800ms return <ProductList products={products} />; } ``` ## Anti-patterns | Anti-pattern | Why it's wrong | Fix | |---|---|---| | `"use client"` at the top of `page.tsx` | Disables RSC for the whole route | Move client logic into a small leaf component | | `useEffect` for initial data | Hydration delay, layout shift, no SSR | Server Component with `await` | | Forms via `onSubmit` + `fetch('/api/...')` | Reinvents Server Actions, no progressive enhancement | Server Action + `useFormState` | | Importing a Server-only library into a Client component | Build error or runtime failure | Wrap usage in a Server Component, pass results as props | | `dynamic(() => import(...), { ssr: false })` everywhere | Defeats SSR + RSC entirely | Use Suspense + Server Component instead, only `ssr: false` for genuinely client-only libs (e.g., charts that read window) | | Sharing modules between Server and Client without `import 'server-only'` | Server secrets can leak into client bundle | Use `import 'server-only'` at the top of any module that must never reach the client | ## Hydration mismatch — debugging cheatsheet When you see "Hydration failed because the initial UI does not match what was rendered on the server": 1. **First suspect: `Date.now()`, `Math.random()`, or `new Date()` in render.** Move to `useEffect`, or compute on server and pass as prop. 2. **Second suspect: `typeof window !== 'undefined'` checks in render.** That's a code smell — split into Client component or use `useSyncExternalStore`. 3. **Third suspect: browser extensions** (Grammarly, dark mode extensions). Suppress with `suppressHydrationWarning` only after eliminating 1 and 2. 4. **Fourth suspect: malformed HTML** (e.g., `<p>` containing a `<div>`). The browser auto-corrects on parse; React doesn't. Run the page through W3C validator. ## Verification checklist - [ ] No `"use client"` higher than necessary - [ ] No `useEffect` for initial data fetching - [ ] Forms use Server Actions where possible - [ ] Slow data wrapped in `<Suspense>` - [ ] No `Math.random()` / `Date.now()` in render - [ ] No `typeof window` checks in render - [ ] `import 'server-only'` on any server-secret module - [ ] First-load JS budget under 100KB on critical pages - [ ] LCP < 2.5s, CLS < 0.1, INP < 200ms (verify with Lighthouse) ## When stuck 1. **Re-read this file from the top.** Most "RSC won't cooperate" issues are decision-tree violations. 2. **Read the component tree as a server/client diagram.** Color server components green, client red. Look for red branches that could be green. 3. **Look up the latest API behavior** via Context7 — RSC semantics are still evolving (especially around caching, `unstable_cache`, `revalidateTag`). 4. **Hand off to Cipher (Frontend Lead)** if the decision is architectural beyond a single feature.
Auf GitHub ansehen