Next.js allows you to lazy load client components, deferring their loading time and only include them in the client bundle when needed. This can be achieved by importing the component and libraries using the dynamic()
method instead of the standard import
statement.
For example, here is how you can dynamically import a client component:
1src
2├── app
3│ ├── error.jsx
4│ ├── favicon.ico
5│ ├── globals.css
6│ ├── layout.jsx
7│ └── page.jsx <===== Webpage
8└── components
9 └── clientComponent.jsx <===== Client component
app/page.js
1import dynamic from "next/dynamic";
2
3const ClientComponent = dynamic(() => import("@/components/clientComponent"));
4
5export default async function Page() {
6 return (
7 <>
8 <p>Hello, World!</p>
9 <ClientComponent />
10 </>
11 );
12}
Try this example on your own computer, and you'll notice that the client component and the rest of the webpage are rendered at the same time. Seems like the client component is not being lazy loaded at all.
This is because of server-side rendering (SSR). As we've discussed before, in Next.js, server components are rendered on the server, and client components are rendered on the client. But in reality, that is not the full story.
By default, in order to provide better SEO and user experience, Next.js will SSR the client component as well. A HTML document will be rendered on the server and when the user requests the page, this HTML document will be sent to the user and Next.js will then inject the corresponding JavaScript code to make it dynamic.
In reality, you can think of it as Next.js server and Next.js client, instead of the actual server and client machines.
For Next.js server components, everything happens on the server, while for the Next.js client components, the rendering happens on the server by default, and Next.js will make the component dynamic on the client by injecting JavaScript code.