How to provide context to React Server Components (Next.js 13.2) ? (e.g. theme)
Asked Answered
S

2

13

I’ve been playing with React Server Components for nearly 2 weeks now and this question has been making my brain hurt: how do you provide context to server components? Like for example, providing a theme (e.g dark | light mode) ? Ive checked the Nextjs docs so many times and ive read the same thing like as if it would change. It states that only the client components can useContext. So how would server components useContext if it needs data thats not server based? I can’t fetch data thats state based. Has anyone figured a way around this?

    <html>
      <body className="page-container">
        <ThemeProvider>
          {children} // Combination of Server and Client components
        </ThemeProvider>
      </body>
    </html>
export default async function ServerComponent(){
 ...
 const theme = useContext(ThemeContext) // Would give an error; not a client component
 ...
 return (
  <div className={theme}>
   ...
  </div>
)
}

I've done everything that was said in the Next.js beta docs: place the provider in a client component and let the server components be the children of said client component. Now, I'm just wondering how to consume the context in server components; it works in client components as they're allowed to use hooks, but not for server components.

Septet answered 17/3, 2023 at 19:23 Comment(2)
See this answer for more information on "server context" vs "client context". React Server Components do not communicate with each other via a normal React context, but by using a request-scoped cache via the "cache" function.Pretzel
Does this answer your question? Retrieve data server side and save in context with Next.jsPretzel
E
1

Recently added an experimental implementation of server contexts to the next-impl-getters package. The implementation API mirrors client contexts, so there should be no difficulties in using them.

The alternative is to use the unstable_cache function.

// ./ExampleContext.ts
import createServerContext from "next-impl-getters/create-server-context"

export const ExampleContext = createServerContext<{ data: string }>()
// ./ParentComponent.ts
import { ExampleContext } from "./ExampleContext"
import ChildComponent from "./ChildComponent"

export default function ParentComponent() {
    return (
        <ExampleContext.Provider value={{ data: 'test' }}>
            <ChildComponent />
        </ExampleContext.Provider>
    )
}
// ./ChildComponent.ts
import getServerContext from "next-impl-getters/get-server-context"
import { ExampleContext } from "./ExampleContext"

export default function ChildComponent() {
    const context = getServerContext(ExampleContext)

    return (
        <div>
            {context?.data}
        </div>
    )
}
Extremist answered 31/1, 2024 at 19:56 Comment(0)
V
0

Context running on client side only, that means you can not use it from server component. You can try to create the client component and import to your the server component by using 'use client'; at first line in your client component.

See for more information: https://beta.nextjs.org/docs/rendering/server-and-client-components#client-components

Hope it helps for you.

Vapor answered 17/3, 2023 at 19:38 Comment(3)
That sort of defeats the purpose of the server component. Also, if we're going to go with a 'theme provider' as the example, the method that you have provided ( in which i said i read the docs and implemented what was recommended ) it would mean that every server component must turn into client components; ultimately, making the whole server components idea useless. The question is how to mitigate that issue: not unnecessarily making server components into client components. ( Thank you, though, for answering )Septet
@JackOats What is your server component intended for? There won't be much difference between the client component and the server component. As far as I know context api is not fully supported at the server component yet and it is not certain that something will change in the near futureVapor
This is valid palliative to solve OP problem but not the ideal solution, indeed defeating the purpose of RSC, see my comment on the answer. Using React 18 "cache" function is the preferred solution until a better API is proposed.Pretzel

© 2022 - 2025 — McMap. All rights reserved.