app/rsc/page.tsxJavaScript// NOTE: *before* Server Components import marked from 'marked'; // 35.9K (11.2K gzipped) import sanitizeHtml from 'sanitize-html'; // 206K (63.3K gzipped) function NoteWithMarkdown({text}) { const html = sanitizeHtml(marked(text)); return (/* render */); }
app/rsc/page.tsxJavaScript// Server Component === zero bundle size import marked from 'marked'; // zero bundle size import sanitizeHtml from 'sanitize-html'; // zero bundle size function NoteWithMarkdown({text}) { // same as before }
app/rsc/page.tsxJavaScriptimport db from 'db'; async function Note({id}) { const note = await db.notes.get(id); return <NoteWithMarkdown note={note} />; }
- Server components cannot use browser-only APIs
- Server components cannot use React hooks
- Server components cannot use Context
app/rsc/page.tsxTypeScript'use client'; import { useState } from 'react'; export default function ExampleClientComponent({ children, }: { children: React.ReactNode; }) { const [count, setCount] = useState(0); return ( <> <button onClick={() => setCount(count + 1)}>{count}</button> {children} </> ); }
app/rsc/page.tsxJavaScript// This pattern works: // You can pass a Server Component as a child or prop of a // Client Component. import ExampleClientComponent from './example-client-component'; import ExampleServerComponent from './example-server-component'; // Pages in Next.js are Server Components by default export default function Page() { return ( <ExampleClientComponent> <ExampleServerComponent /> </ExampleClientComponent> ); }
app/rsc/page.tsxTypeScriptexport const metadata = { title: 'Next.js Tutorial', description: 'A Next.js tutorial using the App Router', }; async function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang={'en'}> <body>{children}</body> </html> ); } export default RootLayout;