Useful Cheatsheetsusefulcheatsheets.com
Next.js Components
Chapter 14 · Page 98
Intermediate

Next.js Components

Build Next.js components using server and client rendering strategies for performance.

TL;DR

  1. 01Server components render on server, no JavaScript sent.
  2. 02Client components (use client) render in browser with state.
  3. 03Combine both for optimal performance and interactivity.

Tips

  1. 01Default to server components for better performance — only use client components when you need interactivity.

Warnings

  1. 01"use client" at the file level makes the entire file client-side — keep client components minimal and separate.
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Components
Chapter 14 · Page 99
Intermediate

Next.js Components

(continued)

Server Component Patterns

  • Server components are the default in App Router.
    // app/components/BlogPost.tsx
    export default async function BlogPost({ slug }) {
      const post = await fetchPost(slug);
      return <article>{post.content}</article>;
    }
  • Can access databases, secrets, and APIs directly.
  • No JavaScript sent to browser for these components.
  • Cannot use hooks or browser APIs.
  • Use async/await directly in the component to fetch data.
    export default async function UserProfile({ id }) {
      const user = await db.user.findUnique({ where: { id } });
      return <p>{user.name}</p>;
    }
  • Pass props from server components to client components safely.
    export default async function Page() {
      const settings = await getSettings();
      return <ThemeProvider theme={settings.theme} />;
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Components
Chapter 14 · Page 100
Intermediate

Next.js Components

(continued)

Interactive Patterns

  • Mark components to render on client with "use client".
    "use client";
    
    import { useState } from "react";
    
    export default function Counter() {
      const [count, setCount] = useState(0);
      return <button onClick={() => setCount(count + 1)}>{count}</button>;
    }
  • Can use React hooks and browser APIs.
  • Must declare at top of file.
  • Use for interactive features.
  • Use useEffect to run code only after the component mounts.
    "use client";
    
    import { useEffect, useState } from "react";
    
    export function Clock() {
      const [time, setTime] = useState("");
      useEffect(() => {
        setTime(new Date().toLocaleTimeString());
      }, []);
      return <p>{time}</p>;
    }
  • Access browser APIs like localStorage inside client components.
    "use client";
    
    export function SaveButton({ data }) {
      function save() {
        localStorage.setItem("draft", JSON.stringify(data));
      }
      return <button onClick={save}>Save Draft</button>;
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Components
Chapter 14 · Page 101
Intermediate

Next.js Components

(continued)

Server and Client Composition

  • Pass server components as children to client components.
    "use client";
    
    export default function Layout({ children }) {
      return <div>{children}</div>;
    }
    
    // children can be server components
    <Layout>
      <ServerComponent />
    </Layout>
  • Keep sensitive data in server components, pass only safe props.
    // Server component fetches and sanitizes data
    export default async function Page() {
      const post = await getPost(); // has private fields
      return <PostCard title={post.title} body={post.body} />;
    }
  • Use context providers at the root for shared client state.
    "use client";
    
    export function ThemeProvider({ children }) {
      const [theme, setTheme] = useState("light");
      return (
        <ThemeContext.Provider value={{ theme, setTheme }}>
          {children}
        </ThemeContext.Provider>
      );
    }
  • Wrap only interactive parts in client components to minimize bundle.
    // app/page.tsx (server)
    import LikeButton from "./LikeButton"; // only this is client
    
    export default async function Post() {
      const post = await getPost();
      return (
        <article>
          <h1>{post.title}</h1>
          <LikeButton postId={post.id} />
        </article>
      );
    }
  • Avoid importing server-only modules in client components.
    import "server-only"; // throws if imported by a client bundle
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Components
Chapter 14 · Page 102
Intermediate

Next.js Components

(continued)

Data Fetching Patterns

  • Fetch in server components for better performance.
    export default async function Products() {
      const res = await fetch('/api/products');
      const products = await res.json();
      return (
        <ul>
          {products.map(p => <li key={p.id}>{p.name}</li>)}
        </ul>
      );
    }
  • Fetch from client for real-time or user-specific data.
    "use client";
    
    import { useEffect, useState } from "react";
    
    export function LiveFeed() {
      const [data, setData] = useState(null);
      useEffect(() => {
        fetch('/api/live-data')
          .then(r => r.json())
          .then(setData);
      }, []);
      return <div>{data?.message}</div>;
    }
  • Use SWR for client-side fetching with caching and revalidation — provide a fetcher that parses JSON.
    "use client";
    
    import useSWR from "swr";
    const fetcher = (url: string) => fetch(url).then(r => r.json());
    
    export function Profile({ id }) {
      const { data, error } = useSWR(`/api/users/${id}`, fetcher);
      if (error) return <p>Error</p>;
      return <p>{data?.name}</p>;
    }
  • Parallel fetch multiple server requests to reduce wait time.
    export default async function Page() {
      const [user, posts] = await Promise.all([getUser(), getPosts()]);
      return <div><UserCard user={user} /><PostList posts={posts} /></div>;
    }
  • Deduplicate fetch calls with the built-in request memoization.
    // Both components call getUser() — fetched only once per request
    async function Header() { const u = await getUser(); return <p>{u.name}</p>; }
    async function Sidebar() { const u = await getUser(); return <p>{u.role}</p>; }
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Components
Chapter 14 · Page 103
Intermediate

Next.js Components

(continued)

Component Organization

  • Separate server and client concerns into different folders.
    app/
      components/
        server/
          BlogPost.tsx   # Server component
          Header.tsx     # Server component
        client/
          Counter.tsx    # Client component
          Modal.tsx      # Client component
  • Keep client components small and focused.
    "use client";
    
    // Only interactive part is client
    export function Favorite({ postId }) {
      const [liked, setLiked] = useState(false);
      return <button onClick={() => setLiked(!liked)}>{liked ? "Liked" : "Like"}</button>;
    }
  • Colocate components near the pages that use them.
    app/
      blog/
        page.tsx
        components/
          PostCard.tsx
          PostList.tsx
  • Export reusable components from a shared ui folder.
    // app/ui/Button.tsx
    export function Button({ children, onClick }) {
      return <button className="btn" onClick={onClick}>{children}</button>;
    }
  • Use index files to simplify imports from component folders.
    // app/ui/index.ts
    export { Button } from "./Button";
    export { Card } from "./Card";
    // import { Button, Card } from "@/app/ui";
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Components
Chapter 14 · Page 104
Intermediate

Next.js Components

(FAQ)

FAQ

Use Client Components when you need browser APIs, event listeners, useState, or useEffect. If your component is purely for rendering data without interactivity, keep it as a Server Component to avoid shipping unnecessary JavaScript to the browser.

Yes — you can import and render Client Components inside Server Components. The boundary only goes one way: Client Components cannot import Server Components, but you can pass Server Components as children or props to Client Components.

The 'use client' directive marks a module boundary — everything imported by that file is also bundled for the client. Extract interactive logic into a small, focused component and add 'use client' only there to keep the rest of the tree server-rendered.

Directly call async functions or await fetch() inside the component body — Server Components are async by default. There's no need for useEffect or SWR; the data is fetched at render time on the server and the result is streamed to the client.

A layout wraps multiple pages and persists across navigation, while a page is the unique UI for a route segment. Both default to Server Components; only add 'use client' if the layout or page itself requires interactivity, otherwise keep data fetching server-side for better performance.