rsc-data-optimizer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

RSC Data Fetching Optimizer

RSC数据获取优化器

Optimize slow client-side data fetching to instant server-side rendering.
将缓慢的客户端数据获取优化为即时服务端渲染。

Quick Diagnosis

快速诊断

Search for these anti-patterns in the codebase:
bash
undefined
在代码库中搜索以下反模式:
bash
undefined

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 load
- `useState(true)` for `isLoading` = user sees spinner
- `useStore()` or `useContext` for initial page data = waterfall fetching
rg -n "useEffect.*fetch|useState.*loading|useStore()" --type tsx rg -n '"use client"' app/ --type tsx

**危险信号:**
- `"use client"` + `useEffect` + `fetch()` = 初始加载缓慢
- `useState(true)` 设置 `isLoading` = 用户会看到加载spinner
- `useStore()` 或 `useContext` 用于初始页面数据 = 瀑布式数据获取

3-Step Conversion Workflow

三步转换流程

Step 1: Identify Data Requirements

步骤1:明确数据需求

Determine what data the page needs on initial render:
  • Static/rarely-changing data → Server Component (SSR)
  • User-interactive data (filters, search) → Client Component
确定页面初始渲染所需的数据类型:
  • 静态/极少变更的数据 → Server Component(SSR)
  • 用户交互型数据(筛选器、搜索) → Client Component

Step 2: Extract Interactive Sections

步骤2:提取交互部分

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>;
}
将包含
useInView
useState
onClick
的部分移至独立的Client Component:
tsx
// components/data-section.tsx
"use client";

interface DataSectionProps {
  data: Item[];  // 以props形式接收数据
}

export function DataSection({ data }: DataSectionProps) {
  const [ref, inView] = useInView();  // 客户端动画可正常使用
  return <div ref={ref}>...</div>;
}

Step 3: Convert Page to Server Component

步骤3:将页面转换为Server Component

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} />;
}
tsx
// app/page.tsx - 不要添加"use client"
import { getData } from "@/lib/actions/data";
import { DataSection } from "@/components/data-section";

export default async function Page() {
  const data = await getData();  // 在服务端获取数据
  return <DataSection data={data} />;
}

Type Adapter Pattern

类型适配器模式

When DB types differ from frontend types:
tsx
import 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} />;
}
当数据库类型与前端类型不一致时:
tsx
import 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} />;
}

When to Keep Client-Side

何时保留客户端获取

Keep
"use client"
when:
  • Real-time subscriptions (Supabase realtime)
  • User-triggered fetching (search, filters, pagination)
  • Data depends on client state (auth token, localStorage)
  • Infinite scroll / load more patterns
在以下场景保留
"use client"
  • 实时订阅(如Supabase realtime)
  • 用户触发的获取(搜索、筛选、分页)
  • 数据依赖客户端状态(认证token、localStorage)
  • 无限滚动 / 加载更多模式

Advanced Patterns

进阶模式

See references/patterns.md for:
  • Parallel data fetching
  • Streaming with Suspense
  • Error boundaries
  • Caching strategies
  • Hybrid SSR + client patterns
查看references/patterns.md了解:
  • 并行数据获取
  • 结合Suspense的流式渲染
  • 错误边界
  • 缓存策略
  • SSR + 客户端混合模式