-
Notifications
You must be signed in to change notification settings - Fork 49.9k
RFC: Server Context for React Server Components #33088
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Thank you for raising this important topic and creating this pull request! I completely agree with the motivation section. Without a proper context solution, Server Components will not be practical to use. Consider a simple example: I have a library with components. When rendered in the header, they should receive one set of props, but when rendered in the body, a different one. In this scenario, the context isn't about state management, but rather about knowing exactly where in the component tree the component is rendered - thus avoiding unnecessary prop drilling. Additionally, it might be beneficial to keep the naming consistent (without the word "Server") to facilitate seamless migration of components between server and client environments. If unified naming isn't feasible, I suggest focusing naming conventions around the meaning of contexts - specifically distinguishing between contexts "without state change" and "with state change." For instance, a name like createRenderContext would clearly indicate that the context provides information about the component’s position within the render tree, irrespective of state changes. |
|
Agreed, this kind of composition isn't possible with server components if This forces you to make bad design decisions due to the inability to use context to share state in a sub-tree. ===== There's an implementation people can use today for server context, albeit it's not pretty import React from "react";
import { cache, ReactNode } from "react";
export type UserContext = {
name: string;
}
const [get, set] = cache((): [() => UserContext , (ctx: UserContext ) => void] => {
let ctx = {} as UserContext ;
return [() => ctx, (value: UserContext ) => (ctx = value)];
})();
export const UserContextServerProvider = ({ value, children }: { value: UserContext ; children: ReactNode }) => {
/* simulates React Context Provider */
set(value);
return <>{children}</>;
};
/* simulates use(Context) */
export const useUserServer= () => get();==== My issue with this proposal is that it's server only. I think the best and only solution is to create a solution that allows us to create context on the server that can be used on the client and therefore caters to more use-cases and doesn't require 2 api's and 2 mental models. This API would only allow JSON serializable contexts (same RSC constraint) and put the context in a script tag similarly to how The reason why I think a isomorphic context solution is required is because it will support use cases like this. Where === TL;DR Isomorphic context solves the points in the motivation section, keeps the API the same (introduces no new APIs), Introduces little or no additional cognitive overhead for reasoning about who can access context where. Finally it has greater flexibility about what you can build with it. |
|
This pull request has been automatically marked as stale. If this pull request is still relevant, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize reviewing it yet. Your contribution is very much appreciated. |
|
uhm...bump, I guess |
|
I've been working with Server Components since they first shipped and have used them exclusively in my library renoun. As detailed in this thread already, a first‑class server context in React would benefit the RSC ecosystem in several ways. This is currently where I see the benefits of reintroducing
<RootProvider git="souporserious/renoun" siteUrl="https://renoun.dev" theme="nord">
...
</RootProvider>The benefits of this are that we can do other orchestration within this component like set up theme/locale providers in one place based on the incoming configuration. This keeps everything colocated and avoids requiring a separate config file.
<pre>
<Tokens>let count = 0;</Tokens>
</pre>
<CodeBlock path="components/Button.tsx"> // reads file contents and passes down to `Tokens` component
<Toolbar /> // gets the name from the path to display
<Tokens />
</CodeBlock>
React Server Components have been an amazing addition to React, but for library authors specifically we need better control of moving around at least short bits of data like configuration around where prop drilling isn't feasible as we've seen with Client Components. |
|
@souporserious - this PR suggests server context through |
|
If we serialize some 'facts' about hydration to js snippets; Like swapping out of order Suspense elements back in order. Is there no precedence to serialize context into a json object and into a script/js snippet? |
This RFC proposes reintroducing Server Context for React Server Components to provide a way to share values across components (including async components) without prop drilling.
Motivation
Server Components introduce async rendering patterns which seems to require a specialized context solution. The absence of such a mechanism causes several problems:
This is especially problematic for component library authors who:
Proposed Solution
A set of APIs specifically designed for Server Components:
Implementation
The implementation leverages Node.js's
AsyncLocalStorageto maintain context across async boundaries:$$typeofsymbol (REACT_SERVER_CONTEXT_TYPE)AsyncLocalStorageis already used successfully in React for resource resolution in server rendering, making it a proven solution for this purpose.Key Use Cases
Performance Considerations
AsyncLocalStorage has minimal overhead and is optimized in Node.js:
Drawbacks
Alternatives Considered
Unresolved Questions
References