Patterns

     

Moving Client Components to the Leaves:

To improve the performance of your application, we recommend moving Client Components to the leaves of your component tree where possible. For example, you may have a Layout that has static elements (e.g. logo, links, etc) and an interactive search bar that uses state.

Instead of making the whole layout a Client Component, move the interactive logic to a Client Component ( e.g. ) and keep your layout as a Server Component. This means you don't have to send all the component Javascript of the layout to the client.

// SearchBar is a Client Component
import SearchBar from './searchbar'
// Logo is a Server Component
import Logo from './logo'

// Layout is a Server Component by default
export default function Layout({ children }) {
  return (
    <>
      <nav>
        <Logo/>
        <SearchBar/>
      </nav>
      <main>{children}</main>
    </>
  )
}

Server and Client Components can be combined in the same component tree.

     

Unsupported Pattern: Importing Server Components into Client Components:

The following pattern is not supported. You cannot import a Server Component into a Client Component:

'use client'

// This pattern will **not** work!
// You cannot import a Server Component into a Client Component.
import ExampleServerComponent from './example-server-component'

export default function ExampleClientComponent({ children }) {
  const [count, setCount] = useState(0)

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

      <ExampleServerComponent/>
    </>
  )
}

Instead, when designing Client Components you can use React props to mark "slots" for Server Components.

The Server Component will be rendered on the server, and when the Client Component is rendered on the client, the "slot" will be filled in with the rendered result of the Server Component.

A common pattern is to use the React children prop to create the "slot". We can refactor to accept a generic children prop and move the import and explicit nesting of up to a parent component.

'use client'

import { useState } from 'react'

export default function ExampleClientComponent({ children }) {
  const [count, setCount] = useState(0)

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

      {children}
    </>
  )
}

Now, has no knowledge of what children is. Infact, from its perspective it doesn't even know that children will eventually be filled in by the result of a Server Component.

The only responsibility ExampleClientComponent has is to decide where whatever children will eventually be should be placed.

In a parent Server Component, you can import both the and and pass as a child of :

// 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>
  )
}

With this approach, the rendering of and are decoupled and can be rendered independently - aligning with Server Components, which are rendered on the server before Client Components.

💡 It is useful to read about The "server only" package