@nimpl/context
Implementation of server contexts in React Server Components without switching to SSR.
Before using the library, read the Possible Issues
Note
Previously, contexts were part of @nimpl/getters, but with the release of react 19, they were moved to a separate package.
Installation
Using npm:
npm i @nimpl/context
Stability
Package covered with tests. Tests are run on every release and every 6 hours on the latest Canary version of Next.js
.
In this way, you can be sure that if there is a breaking change in Next.js
, this will immediately become known. Even before the release of a stable version of Next.js
.
Note
The package uses node
AsyncLocalStorage
instead ofreact cache
for the reason that cache from react.js works for the entire page as a whole. The current implementation allows to fully reproduce the logic of react client contexts. That is, contexts are available only inside the DOM from the provider, including for asynchronous components.
How to
Important
Since next.js builds Layout and Page independently, they cannot have a single context. That is, you need to initiate the context in both
layout.tsx
andpage.tsx
1. Initialize the context
import createServerContext from "@nimpl/context/create-server-context"
export const ExampleContext = createServerContext<{ data: string }>()
2. Transfer the data to the provider
import { ExampleContext } from "./ExampleContext"
import ChildComponent from "./ChildComponent"
export default function ParentComponent() {
return (
<ExampleContext.Provider value={{ data: 'test' }}>
<ChildComponent />
</ExampleContext.Provider>
)
}
3. Get context data
import getServerContext from "@nimpl/context/get-server-context"
import { ExampleContext } from "./ExampleContext"
export default function ChildComponent() {
const context = getServerContext(ExampleContext)
return (
<div>
{context?.data}
</div>
)
}
3.1. You can also use a consumer to get context data
import { ExampleContext } from "./ExampleContext"
import ChildComponent from "./ChildComponent"
export default function ParentComponent() {
return (
<ExampleContext.Provider value={{ data: 'test' }}>
<ExampleContext.Consumer>
{(data) => {
//...
return <ChildComponent />
}}
</ExampleContext.Consumer>
</ExampleContext.Provider>
)
}
Possible Issues
Layouts don't re-render
As a potential risk of a server-side solution, the problem of Layouts is mentioned, that they do not re-render, which is inherent in the app router foundation. I don't see any reason to change this logic.
The most reliable approach, in my opinion, is to output messages to the console or even throw an error when this function is used in Layout or Error without the necessary conditions.
Since at the moment it is impossible to determine in which route the component is rendered - there are no automatic errors. However, it is strongly discouraged to use this feature in layouts.
Context loosing
The functionality of node.js, used within contexts can lose content: "In rare situations, the current store is lost in one of the asynchronous operations" (nodejs docs ).
A similar approach is used in dozens of places inside nextjs. But if you have experience with this issue - please share in the issues and discussions of the package.
Examples
You can see examples in the package repository .
Development
Read about working on the package and making changes on the contribution page
Additional
Please consider giving a star if you like it, it shows that the package is useful and helps continue work on this and other packages.
Create issues with wishes, ideas, difficulties, etc. All of them will definitely be considered and thought over.