We’ve recently rebuilt our website with NextJS V13 app directory, and what a journey it was! As app directory is(at the time of writing this article) in beta, it wasn’t all smooth sailing, but once we got the hang of it - our website speed improved by quite a lot. To help other developers starting with NextJS 13, we’ve compiled a list of 10 of the most important lessons we learned. You can use those as mental guidelines for writing performance NextJS 13 code.
Read all the available documentation before writing any code.
Often when we see a cool new feature, we want to build something with it right away, hoping to learn it in the process. If the deadlines are tight, it seems even more viable.
But NextJS 13 introduces many new concepts, which are pretty high-level, so the biggest recommendation is to read ALL of the available documentation before writing any code. And then reread this documentation as needed. Here are some of our favorite sources(in the order that we’d recommend reading them)
- React documentation on Server Components(used be NextJS 13 under the hood)
- Difference between SSR and React Server Components
- Main takeaways of React Server Components
- NextJS Docs
- HackerNews(Dan Abramov answered some of the comments!)
Minimize the amount of client components
In general, less client components - more performance. Before creating a new page, we suggest making a high-level overview of what that page will look like.
For example, you want to build a simple “Contact Us” form with a react-hook-form and some Captcha library. The Captcha library's provider component requires you to write ‘use client’. The simplest way of creating that page would be
page.tsx
'use client'
function Page() {
return (
<CaptchaProvider>
<SomeStaticContent/>
<form>
...react-hook-form
</form>
</CaptchaProvider>
)
}
Setting ‘use client’ for the whole page is a bad practice. But even if our <CaptchaProvider/>
is a Client Component, you can pass a Server Component as a child or prop of a Client Component
From React docs
A Server Component may pass another Server Component as a child to a Client Component:
<ClientTabBar><ServerTabContent /></ClientTabBar>
. From the Client Component’s perspective, its child will be an already rendered tree, such as theServerTabContent
output. This means that Server and Client components can be nested and interleaved in the tree at any level.
This means only <CaptchaProvider/>
needs to be a Client component. As per NextJS docs, we can wrap our provider in our own client component
customCaptchaProvider.tsx
'use client'
import { CaptchaProvider } from 'captcha-library'
export default CaptchaProvider
Now we can remove the ‘use client’ from page.tsx
page.tsx
import OurCaptchaProvider from './customCaptchaProvider'
function Page() {
return (
<OurCaptchaProvider>
<SomeStaticContent/>
<form>
...react-hook-form
</form>
</OurCaptchaProvider>
)
}
But, react-hook-form relies on useRef
under the hood, which can’t be used in a Server Component. We can extract the form into a separate client component
ContactUsForm.tsx
'use client'
function ContactUs() {
return (
<form>
...react-hook-form
</form>
)
}
page.tsx
import OurCaptchaProvider from './CustomCaptchaProvider'
import ContactUs from './ContactUsForm'
function Page() {
return (
<OurCaptchaProvider>
<SomeStaticContent/>
<ContactUs/>
</OurCaptchaProvider>
)
}
If <SomeStaticContent>
is a small component, the difference won’t be that big, but the larger it gets, the more noticeable the difference will become. As a rule of thumb, you should try to make every component a Server Component first and resort to Client Components if you can’t.
Get comfortable with SWR or React Query for fetching on the client
Client components don’t support fetch()
yet, so you’ll have to use either SWR or React Query for fetching data in Client Components. If you aren’t very familiar with those libraries, we’d recommend trying them out in a regular React project first to get comfortable with the fundamentals and choose the library that works for you. For MiKi website, we went with SWR, and it was a pretty smooth experience, so this might be a good starting point.
In Server Components, you can use fetch()
without any issues since Server Components support async/await right inside the component. As a general rule, NextJS recommends fetching data in Server Components as much as possible.
Change your “stance” against npm packages
Using npm packages greatly improves the development speed. But remember the time when before installing some library, you had to check https://bundlephobia.com/ to see how it would affect bundle size and page load time? So many developers became against the excessive use of npm packages, as it can make your bundle size bigger, leading to slower compile and load times.
Since Server Components are run only on the server, they don’t impact bundle size. With this in mind, you should be more open to using npm packages - this will save time and bring us to a more modular future where the functionality you need to be may already exist in npm. Even if the library weighs a lot, you can use it in Server Components without negatively affecting the bundle size.
However, you have to remember that this is only true for Server Components, using a big library in a Client Component will still negatively affect your bundle size. As we advised earlier - try to make as few Client Components as possible.
Thank you for reading
Those were the four most important tips we wanted to share. Hope they’ll make you a better NextJS 13 developer. If you have any questions or suggestions, feel free to leave them in the comments.
At MiKi we help businesses make stunning websites with a blazing-fast and cost-efficient cloud backend.
Interested?
Feel free to give us a call at +447588739366, book a meeting at https://lnkd.in/gGmfJu8z or feel out the contact form at our website https://www.miki.digital/contact
Top comments (0)