Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Optimize Next.js App Router data fetching by converting slow client-side fetching to fast server-side fetching using React Server Components (RSC). Use when: - User reports slow initial page load with loading spinners - Page uses useEffect + useState for data fetching - StoreContext/useStore pattern causes waterfall fetching - Need to improve SEO (content not in initial HTML) - Converting "use client" pages to Server Components Triggers: "slow loading", "optimize fetching", "SSR data", "RSC o
.claude/skills/microck-rsc-data-optimizer/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 5% | 0% |
| case-06 | ✓→✗ | ▼ Worse | -9% | 0% |
| case-16 | ✓→✗ | ▼ Worse | -15% | 0% |
| case-11 | ✓→✓ | = Same ✓ | -6% | 0% |
| case-12 | ✓→✓ | = Same ✓ | 34% | 0% |
Optimize slow client-side data fetching to instant server-side rendering.
Search for these anti-patterns in the codebase:
bash# Find client-side fetching patterns rg -n "useEffect.*fetch|useState.*loading|useStore\(\)" --type tsx rg -n '"use client"' app/ --type tsx
Red flags:
"use client" + useEffect + fetch() = slow initial loaduseState(true) for isLoading = user sees spinneruseStore() or useContext for initial page data = waterfall fetchingDetermine what data the page needs on initial render:
Move sections with useInView, useState, onClick to separate Client Components:
tsx// components/data-section.tsx "use client"; interface DataSectionProps { data: Item[]; // Receive data as props } export function DataSection({ data }: DataSectionProps) { const [ref, inView] = useInView(); // Client-side animation OK return <div ref={ref}>...</div>; }
tsx// app/page.tsx - NO "use client" import { getData } from "@/lib/actions/data"; import { DataSection } from "@/components/data-section"; export default async function Page() { const data = await getData(); // Fetch on server return <DataSection data={data} />; }
When DB types differ from frontend types:
tsximport type { Item as DBItem } from "@/lib/database.types"; import type { Item } from "@/lib/types"; function adaptDBToFrontend(db: DBItem): Item { return { id: db.id, name: db.name, description: db.description ?? "", createdAt: new Date(db.created_at), }; } export default async function Page() { const dbItems = await getItems(); const items = dbItems.map(adaptDBToFrontend); return <ItemList items={items} />; }
Keep "use client" when:
See references/patterns.md for:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-11 | pass→pass | 12,518 | 7,339 | -41% | 1 | 1 | 0% | 2,264 | 2,118 | -6% | 0 | 0 | — |
case-12 | pass→pass | 11,063 | 10,775 | -3% | 1 | 1 | 0% | 1,900 | 2,546 | +34% | 0 | 0 | — |
case-13 | pass→pass | 11,536 | 7,807 | -32% | 1 | 1 | 0% | 2,047 | 2,166 | +6% | 0 | 0 | — |
case-01 | fail→pass | 18,215 | 16,038 | -12% | 1 | 1 | 0% | 3,386 | 3,547 | +5% | 0 | 0 | — |
case-02 | fail→fail | 9,761 | 6,172 | -37% | 1 | 1 | 0% | 1,730 | 1,693 | -2% | 0 | 0 | — |
case-03 | pass→pass | 21,257 | 14,183 | -33% | 1 | 1 | 0% | 3,402 | 2,974 | -13% | 0 | 0 | — |
case-04 | pass→pass | 14,595 | 12,162 | -17% | 1 | 1 | 0% | 2,546 | 2,709 | +6% | 0 | 0 | — |
case-05 | pass→pass | 13,790 | 10,066 | -27% | 1 | 1 | 0% | 2,332 | 2,651 | +14% | 0 | 0 | — |
case-06 | pass→fail | 11,734 | 8,399 | -28% | 1 | 1 | 0% | 2,461 | 2,248 | -9% | 0 | 0 | — |
case-07 | pass→pass | 16,490 | 9,179 | -44% | 1 | 1 | 0% | 2,903 | 2,280 | -21% | 0 | 0 | — |
case-08 | pass→pass | 13,480 | 10,273 | -24% | 1 | 1 | 0% | 2,296 | 2,375 | +3% | 0 | 0 | — |
case-09 | pass→pass | 13,468 | 10,698 | -21% | 1 | 1 | 0% | 2,249 | 2,501 | +11% | 0 | 0 | — |
case-10 | pass→pass | 15,178 | 16,100 | +6% | 1 | 1 | 0% | 2,622 | 3,544 | +35% | 0 | 0 | — |
case-14 | pass→pass | 9,912 | 7,253 | -27% | 1 | 1 | 0% | 1,856 | 1,957 | +5% | 0 | 0 | — |
case-15 | fail→fail | 5,709 | 3,408 | -40% | 1 | 1 | 0% | 1,041 | 1,273 | +22% | 0 | 0 | — |
case-16 | pass→fail | 13,026 | 8,058 | -38% | 1 | 1 | 0% | 2,560 | 2,165 | -15% | 0 | 0 | — |
case-17 | pass→pass | 10,104 | 9,497 | -6% | 1 | 1 | 0% | 1,809 | 2,321 | +28% | 0 | 0 | — |
case-18 | pass→pass | 11,067 | 10,453 | -6% | 1 | 1 | 0% | 1,957 | 2,618 | +34% | 0 | 0 | — |
case-19 | pass→pass | 9,524 | 8,386 | -12% | 1 | 1 | 0% | 1,750 | 2,135 | +22% | 0 | 0 | — |
case-20 | pass→pass | 16,437 | 11,649 | -29% | 1 | 1 | 0% | 2,848 | 2,763 | -3% | 0 | 0 | — |
case-21 | pass→pass | 14,692 | 12,629 | -14% | 1 | 1 | 0% | 2,534 | 2,946 | +16% | 0 | 0 | — |
case-22 | pass→pass | 10,030 | 5,899 | -41% | 1 | 1 | 0% | 2,122 | 1,769 | -17% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of -5 percentage points is the difference between those two pass rates over the 22 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.