Don’t get me wrong, Next.js is great. I love it. It works. I don’t need to deal with routing because it’s already baked into the framework. You can write APIs and the inner workings won’t be exposed on the client side. It’s also React without being React.
But sometimes, you just need it to act and behave like React.
Yes, Next.js is React but when I was making my to-do app I found myself in a conundrum. I needed a component to load on the client rather than on the server.
By default, Next.js pre-renders everything on the server and sends it over to the client. After that, it works just like normal React with client-side rendering.
But what if you need something to load on the client? What if you can’t have the component set itself up on the server side and it needs to be done in the browser?
This is where dynamic()
importing comes in.
Understanding how Next.js rendering works
By default, Next.js renders the requested page on the server and then sends it to the client. Then React takes with client side rendering for the rest of the site. This process is called React hydration.
So rather than seeing the usual empty Loading...
text between a pair of simple <div>
, we get a fully formed HTML page followed by React capabilities. It’s great for the bots while remaining fully functional and interactive for users.
In contrast, client side (aka, just React as we know it), works like this:
📌 Step 1: Starts with HTML shell
📌 Step 2: browser fetch JS files containing React
📌 Step 3: content gets rendered and made interactive
There’s a misconception that you have to do one or the other when it comes to client side vs. server side rendering. However, the perk of using Next.js is that you can mix and match rendering methods as needed on that first load.
How dynamic import works
When you compose your view, you’re likely going to import
parts of it from within your project. Some are fine to render on the server. Some need to be loaded on the client for whatever reason.
Dynamic importing lets you load on the client side and is downloaded in a separate batch file. The perks of doing this are:
- reduces the initial page load size
- is only imported when called in the code
- only fetched when the component is component is rendered for the first time
- rendered imports don’t trigger another fetch, so no new server requests once it's loaded
By default, React bundles everything in through static importing. This means that everything is bundled together when it gets delivered to the client. In contrast, dynamic import lets you do the equivalent of ‘lazy loading’ your modules.
Using dynamic loading beyond the first load
Dynamic loading in Next.js isn’t just limited to the first-page load. You can use it in other places to reduce the initial bundle size.
Dynamic loading is often used to load only what you need. It’s a process of deferring the act of loading resources to reduce the size of the initial app. This allows it to be more responsive and feel like it's loading faster for users.
While you can use the defer
attribute from JavaScript, dynamic imports is a better solution.
Dynamic importing is not a React-specific or Next.js thing but is a JavaScript feature introduced in ES2020. Next.js does have its own implementation of it, so the syntax is a little bit different from how you’d write it in vanilla JavaScript.
👉 Vanilla JavaScript syntax for dynamic importing
// Statically imported module (compile time)
import someStaticModule from 'some/module';
// Dynamically imported module (runtime)
(async () => {
const { export1, export2 } = await import('path/to/some/module');
})();
How to implement dynamic import in Next.js for CSR
Without further ado, here’s what you’re probably after.
👉 The syntax for dynamic importing in Next.js is this:
const YourComponent = dynamic(() => import(<"./somefile"));
👉 You will also need to import dynamic
your export
.
import dynamic from "next/dynamic";
👉 Then just use your component as per usual:
<YourComponent />
Dynamic imports with React.lazy
Alternatively, you can also dynamically import using React’s lazy
module. It’s a similar concept and syntax structure.
Just a note: Next.jsdynamic
is an extension of React’slazy
. The major difference is thatdynamic
also incorporatesSuspense
so that components can delay hydration until the Suspense boundary is resolved. Suspense lets your component “wait” for code to load or until a certain condition is met.
👉 The syntax for React lazy
dynamic importing
const MyLazyComponent = lazy(() => import('path/to/component'));
👉 Remember to import lazy
from React, or else it won’t work
import { lazy } from 'react';
👉 Use component as per usual
<MyLazyComponent />
That’s basically it for client-side module loading in Next.js.
I hope you’ve found this piece helpful. Thank you for making it to the end.