Can I use Server Component with a global Context? #42301
Replies: 10 comments 38 replies
-
As I understand it what you're doing should theoretically work. You can have client components that take server components as children. See https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md#capabilities--constraints-of-server-and-client-components |
Beta Was this translation helpful? Give feedback.
-
Nice. Thank you! @krall12 |
Beta Was this translation helpful? Give feedback.
-
I asked the same question in regards to i18n this week on Twitter: https://twitter.com/jamannnnnn/status/1587835293989732352. It seems to me like having to switch to client components to be able to use context is very much at odds with enabling as many components as possible to stay on the server side. I'm currently looking for such a capability in order to bring RSC support to |
Beta Was this translation helpful? Give feedback.
-
We now have documentation on Context: https://beta.nextjs.org/docs/rendering/server-and-client-components#context |
Beta Was this translation helpful? Give feedback.
-
I've made a small utility for this using |
Beta Was this translation helpful? Give feedback.
-
I also think it'd be nice to see a per request server context made available in some form. I'm new to Next and was pretty baffled that the docs discount the need. There are plenty of uses beyond i18n. For example, I tried to build a serverside caching singleton (the suggested fetch/cache solution or prop drilling is simple for my needs) but ran up against a wall trying to keep it alive from beginning to end of a request (and not persist between requests). |
Beta Was this translation helpful? Give feedback.
-
Hello! We have some documentation here on recommended patterns for using React Context: https://beta.nextjs.org/docs/rendering/server-and-client-components#context |
Beta Was this translation helpful? Give feedback.
-
This became a blocker for us just recently. We're aiming to build an architecture where our standalone component library only depends on a generic data provider interface without binding to any specific implementation. Each environment where the component library is then used (including but not limited to NextJS projects) would provide their own implementation of the data provider. A similar need exists when it comes e.g. to theming or even the link component implementation (given that NextJS apps benefit from NextJS links, but other apps might use something else). Originally we set out to use context for this, but as others already noted it won't work on the server. Here's a workaround that seemed to work so far, although it is somewhat cursed and might lead to rehydration issues down the line if we're not careful, as we now can provide a different data provider instance on the client & server (which could lead to different rendering results between the two): thunderstore-io/thunderstore-ui#744 I don't particularly like having to implement a workaround in the first place, it'd be great if NextJS would support something to enable the kind of pluggable architecture we're looking to implement. |
Beta Was this translation helpful? Give feedback.
-
Ran into this as well when trying to build a feature flagging SDK, which requires a shared "context" for the duration of the request that can hold the current user and flag configuration data. The solution I ended up landing on was basically to "curry" the whole interface of the SDK via a setup function that defines how to obtain the user for the current request. You can see that in action here and view the source code implementation here. It basically looks like this // export "curried" functions that are scoped to use the options passed here
export const { getVariableValue } = setupDevCycle({
sdkKey: 'some-key',
userGetter: async () => {
const userIdentity = headers().get('user-id')
return {
user_id: userIdentity
}
}
}) The reason this works is that all the methods that are exported from that setup function end up calling an "ensure initialization" function which performs things like fetching the current configuration and current user data according to the configured options. It then memoizes the results using the React Now the interface within a server component becomes: // import the "curried" function from the file where the setup function is called
import { getVariableValue } from './devcycle'
export default async ServerComponent() {
// this function can be called with just the details of the flag we want to evaluate. It already knows the current user's data and
// what the flagging configuration is
const variableValue = await getVariableValue('someKey', false)
// do something with the value
} Hopefully this helps someone, I was stuck on this for a while. |
Beta Was this translation helpful? Give feedback.
-
Exactly today I struggled with a similar challenge. After only studying the docs (@leerob linked to them) I was even more confused. The docs are excellent in my opinion and they get better almost every day. Forgive me, if I missed the point, I did not read the whole conversation, but I'll focus now on the initial post. @hucancode said:
Right, but to "switch back" to React Server Components, you have this "slot pattern" Supported Pattern: Passing Server Components to Client Components as Props, which is not helpful at the first view. To use React Context you place a custom client context provider in your RootLayout, or somewhere close to the component root. But now everything enclosed in this lets say Yes and no. This is not true for PageComponents
So you still can continue with nested pages as Server Components and access the context in even deeper nested client components. But what, if you want to access the Context in a Server Component? You use this "slot pattern" and forward the context values as props to the React Server Component. This was a "quicky", so hopefully did not oversee things.
@leerob You have this very helpfull "Good to know" sections in the docs. If It is not just me, who was a bit confused by the fact that Client Components can not import Server components, perhaps it's worth adding a hint. |
Beta Was this translation helpful? Give feedback.
-
I am seeing the whole point of Server Component is that it gets rendered on the server. But what if I want to implement i18n, or theme context, or anything that requires having a global context.
Take this
app/layout.jsx
for example, I want to have anI18n
context available site-wide, so I can translate whatever text whenever I want.The
I18n
component is implemented as so, usingcreateContext
, I am forcing myself to abandon Server Component.As what I understand, this approach forces almost everything to be client component, child of a client component has to be client component, right?
Do we have any solution to implement global context but still render on server whenever possible?
Beta Was this translation helpful? Give feedback.
All reactions