All skills
Skillintermediate

React Server Components

```tsx // app/page.tsx - Server Component by default import { db } from '@/lib/db'

Claude Code Knowledge Pack7/10/2026

Overview

React Server Components

Server Components (Default)

// app/page.tsx - Server Component by default

  // Data fetching in Server Component
  const users = await db.user.findMany()

  return (
    <div>
      <h1>Users</h1>
      <ul>
        {users.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  )
}

Benefits of Server Components

  • Zero bundle size - Server Components don't add JavaScript to client bundle
  • Direct backend access - Query databases, read files, use secrets
  • Automatic code splitting - Only Client Components add to bundle
  • Streaming - Send UI progressively as data loads
  • No client-side waterfalls - Fetch all data in parallel on server

Client Components

// components/counter.tsx
'use client' // Required directive

  const [count, setCount] = useState(0)

  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  )
}

When to Use Client Components

Use 'use client' when you need:

  • Interactivity - onClick, onChange, event handlers
  • State - useState, useReducer
  • Effects - useEffect, useLayoutEffect
  • Browser APIs - localStorage, window, document
  • Custom hooks - Any hook using client-only features
  • Class components - Component lifecycle methods

Composition Pattern

// app/page.tsx - Server Component

  const data = await db.query()

  return (
    <div>
      
      <h1>Server Content</h1>

      
      
        
        
      
    </div>
  )
}

// components/client-wrapper.tsx
'use client'

  children,
  initialData,
}: {
  children: React.ReactNode
  initialData: Data
}) {
  const [data, setData] = useState(initialData)

  return (
    <div>
      
      <button onClick={() => refresh()}>Refresh</button>
      
      {children}
    </div>
  )
}

Streaming with Suspense

// app/page.tsx

  return (
    <div>
      
      

      
      Loading...</div>}>
        
      
    </div>
  )
}

// components/slow-component.tsx
async function getData() {
  await new Promise(resolve => setTimeout(resolve, 3000))
  return { data: 'Loaded!' }
}

  const data = await getData()
  return <div>{data.data}</div>
}

Parallel Data Fetching

// app/dashboard/page.tsx
async function getUser() {
  return fetch('https://api.example.com/user')
}

async function getPosts() {
  return fetch('https://api.example.com/posts')
}

  // Fetch in parallel
  const [user, posts] = await Promise.all([
    getUser(),
    getPosts(),
  ])

  return (
    <div>
      
      
    </div>
  )
}

Sequential Data Fetching

// app/artist/[id]/page.tsx
async function getArtist(id: string) {
  return fetch(`https://api.example.com/artists/${id}`)
}

async function getAlbums(artistId: string) {
  return fetch(`https://api.example.com/artists/${artistId}/albums`)
}

  // Sequential: albums depends on artist
  const artist = await getArtist(params.id)
  const albums = await getAlbums(artist.id)

  return (
    <div>
      <h1>{artist.name}</h1>
      
    </div>
  )
}

Preloading Data

// lib/data.ts

  return db.user.findUnique({ where: { id } })
})

// components/user-profile.tsx

  const user = await getUser(userId)
  return <div>{user.name}</div>
}

// app/page.tsx

  // Preload
  getUser('123')

  return (
    <div>
      
      
    </div>
  )
}

Server Component Patterns

Pattern: Layout with Data Fetching

// app/dashboard/layout.tsx

  children,
}: {
  children: React.ReactNode
}) {
  const session = await auth()
  const user = await db.user.findUnique({ where: { id: session.userId } })

  return (
    <div>
      
      <main>{children}</main>
    </div>
  )
}

Pattern: Conditional Client Components

// app/page.tsx

  const data = await fetchData()

  // Only render Client Component when needed
  if (data.requiresInteractivity) {
    return 
  }

  return <div>{data.content}</div>
}

Pattern: Server Component with Client Island

// app/blog/[slug]/page.tsx

  const post = await getPost(params.slug)

  return (
    <article>
      
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />

      
      
    </article>
  )
}

Context in Server/Client Components

// app/providers.tsx
'use client'

  return {children}
}

// app/layout.tsx

  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html>
      <body>
        {children}
      </body>
    </html>
  )
}

Third-Party Components

// components/carousel-wrapper.tsx
'use client'

  return 
}

// app/page.tsx

  const items = await fetchItems()
  return 
}

Edge Runtime

// app/api/route.ts

  return new Response('Hello from Edge!')
}

// app/page.tsx

  return <div>Edge-rendered page</div>
}

Quick Reference

CapabilityServer ComponentClient Component
Data fetching✅ Yes⚠️ Use SWR/React Query
Backend access✅ Yes (DB, files)❌ No
Event handlers❌ No✅ Yes
State/Effects❌ No✅ Yes
Browser APIs❌ No✅ Yes
Bundle size0 KBAdds to bundle
Streaming✅ Yes❌ No

Best Practices

  1. Default to Server Components - Only use 'use client' when needed
  2. Move Client Components down - Push them to leaves of component tree
  3. Pass data down - Fetch in Server Components, pass to Client Components
  4. Use composition - Nest Server Components inside Client Components via children
  5. Cache expensive operations - Use React cache() for deduplication