React contexts are quite crucial for React development. Most projects depends on it, either directly or through libraries. The question is, can they be used with Next.js 13 App Router? And can the application still benefit from the power of Server Components when contexts are used? Let's answer that!
In This Article
- Difference Between Client and Server Components
- Can I Use React Context in Server Components?
- Will My Complete Next.js Application Be Rendered on Client if I Use React Contexts?
Errors Received When Migrating Next.js 13 to New App Folder
Dennis Persson ・ Jun 18 '23
Difference Between Client and Server Components
For this article to make sense, you should have grasp about what the difference between Client Components and Server Components are. In Short, Client Components are regular old React components rendered with JavaScript on the client, while Server Components are React components which are rendered into HTML on the server. The rendered Server Components can then be used as none-interactive components anywhere in the applications React tree.
Does it make sense? If not, you can learn more about Server Components, read Next.js docs about it or my article about, why Server Components matter.
Can I Use React Context in Server Components?
React contexts are well used in React applications to share states between components. Since Client Components and Server Components are rendered on different machines, the client and the server, you might think that React contexts cannot be used.
Server Components are simply HTML markup which certainly don't have a React state. If you try to use a context in a Server Component it will throw an error.
ReactServerComponentsError:
You're importing a component that needs useContext. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
-[/path/to/file/MyComponent.ts:1:1]
1 | import { useContext } from 'react'
While Server Components are incompatible with React contexts, Client Components can handle them perfectly fine. As long as you provide the context provider in a Client Component, all Client Components in that component's child-tree will be able to read and use the context. It doesn't matter whether you have any Server Components in the sub-tree or not, Server Components are HTML markup, which don't care!
It's not you, he's always like that...
Why Server Components - A Brief History of Web
Dennis Persson ・ Jul 9 '23
Will My Complete Next.js Application Be Rendered on Client if I Use React Contexts?
The answer is no. Your whole site will not be forced to render on the client if you use React contexts. As mentioned, Server Components do not care about contexts, which also means it doesn't interfere with them.
Let's list a few statements about Next.js App Router.
- The RootLayout in Next.js is always a Server Component
- The children prop passed to RootLayout is also a Server Component
- Server Components can include Client Components (the Client Components will be ignored when the server renders the Server Component)
- Server Components can be included in Client Components if they are passed as children to the Client Component
Now look at this code example, it's taken from Next.js guide for how to set up contexts.
import { ContextProviders } from './providers';
export default function RootLayout({ children }) {
return (
<html>
<body>
<ContextProviders>{children}</ContextProviders>
</body>
</html>
);
}
What we can see in that code is:
- The Root Layout, which is a Server Component by statement #1
- The ContextProviders component which includes the contexts is a Client Component (statement #3 allows that)
- The children prop for the RootLayout is a Server Component (statement #2)
- The children is passed to the ContextProviders Client Component (accepted by statement #4)
By default, Next.js can handle intervened Client and Server Components, and with this setup we are following all the rules of how to use the components. The above code will result in a React tree looking as below.
<RootLayout (Server Component)>
<ContextProviders (Client Component)>
<Page (Server Component)>
<Potential other Client Components using the context />
<Potential other Server Components ignoring the context />
</Page>
</ContextProviders>
</RootLayout>
Although using contexts work fine, it does create a bit of confusion. You must remember that you will only be able to use the context within Client Components, the context is not available on the server.