/layout.js @ 1688734135567 [Home]

Importing Server Components into Client Components

Okay, pay attention. This is where people get confused.

  1. Client Components can import "Server Components" as long as they can also run in the browser (they don't use Server-Only features).
  2. Client Components cannot import "Server Components" that use Server-Only features.
  3. This is because any Component imported into a Client Component is forced to be treated as a Client Component.

Example of #1

Server Component content
This is a Client-Side Component and this its imported Server Component:
Server Component content

Above, the first box is the ServerComponent rendered server-side, as a RSC. The second box is the ClientComponent, which imports the same ServerComponent and renders it client-side.

If you View Source you will see that both exist in the generated html, because the Client Component was SSR'd. But the Virtual DOM contains a reference to the client component for the second box.

ClientComponent.js
'use client'
import {ServerComponent} from "./ServerComponent";

export const ClientComponent = ({children}) => {
  return <div className={"box client-component"}>
    This is a Client-Side Component and this its imported Server Component:
    <ServerComponent/>
  </div>
}
ServerComponent.js
export const ServerComponent = ()=><div className={"box"}>Server Component content</div>;

Here, the "Server Component" doesn't do anything that can't also run in the browser. It doesn't use the filesystem, connect to a database, etc.

It doesn't have a 'use client' directive at the top, but because it's imported into a Client Component, it becomes a Client Component.

So it doesn't really make sense to say ServerComponent.js "IS A" Server Component. It's neither and it's both. It's executed "AS A" Server Component, and it's also executed "AS A" Client Component.

So There Are No "React Server Components"?

No, not literally. There is no declaration like 'use client' at the top of a file that says it must be run on the server. There is no equivalent 'use server'. (Server Functions use the 'use server' syntax, but that is different. More on that later.)

A component is run "AS A" RSC. Some components can only be run "AS A" RSC because they use server-only functions. Yes, in some sense, that could mean it "IS A" RSC. The terminology is a bit ambiguous, which causes problems.

Don't think of RSC as defining a type of thing. Think of it as the label of an environment where React can be run on a server.

Example of #2

Slightly modified versions of the components above demonstrate what happens when you try to import a server-only Component into a Client Component.

ClientComponentImportServerOnly.js
'use client'
import ServerComponent from "./ServerOnlyComponent";

export const ClientComponentImportServerOnly = ({children}) => {
  return <div className={"box client-component"}>
    This is a Client-Side Component and this its imported Server Component:
    <ServerComponent/>
  </div>
}
ServerOnlyComponent.js
import 'server-only';
import {ServerComponent} from "./ServerComponent";
export default ServerComponent;

The ServerOnlyComponent above uses a module called 'server-only' which will throw an error during the build process if it detects that this component is being imported into a Client Component.

Although there is no top-level 'use server' directive, this serves that purpose. If we try to use the Client Component:

<ClientComponentImportServerOnly/>

then we get the following error:

New Mental Model

The One Rule To Remember

The deciding factor for what is treated as a Client Component is what is imported in the code, not how components are nested in the JSX.

async Server Components