> As I write this, there's only one way to start using React Server Components, and that's with Next.js 13.4+
I don't understand how this is acceptable to the React user community, that only Vercel gets to be in this privileged position. Why did they not include other companies, or the users themselves, in the discussion and development of this feature.
> Since Server Components are a new React feature, third-party packages and providers in the ecosystem are just beginning to add the "use client" directive to components that use client-only features like useState, useEffect, and createContext.
> Today, many components from npm packages that use client-only features do not yet have the directive. These third-party components will work as expected within Client Components since they have the "use client" directive, but they won't work within Server Components.
The arrogance of expecting all third-party packages, React-related or not, to buy into the "use client" directive. A humbler approach would have been a "use server" directive to opt-in to this behavior, instead of expecting the entire rest of the ecosystem to adapt to it.
The reason Vercel was selected for this privilege is pretty simple, to my understanding: they volunteered and committed engineering resources to partner with the React team to work through a pretty major and experimental new API with a lot of expected breaking changes.
Third-party packages don't need any directives unless they specifically want to put a client/server boundary in their component.
The directive marks where the transition from server to client happens. If you aren't already starting in a server component, then you don't need to do anything to use client features.
> If you aren't already starting in a server component, then you don't need to do anything to use client features.
This is a deceptive reply since the only RSC implementation in existence starts from a server component.
That means that having React State, a basic building block of React that's leveraged massively across the ecosystem, is broken by default until the user adds a "use client" directive.
They're 100% right that "use server" should have been the directive, and more specifically it should have been something like "use non-interactive". Server vs Client is already widely understood to be tied to SSR in a completely orthogonal manner.
RSC has a much narrower value proposition that shouldn't have gotten muddied by all this.
The design you're suggesting doesn't work because it would cause server/client waterfalls everywhere, which goes against the entire purpose of the architecture.
The data flows in one direction: from the server to the client. It's just physics — your server is where the data is. You're trying to move it to the client. So the code that needs to run first is the server code.
This is why the data flow starts at the server. You can't fix this by changing how opting in works, or some other API design workaround. What you're fighting with is the arrow of time.
There's nothing about it "that doesn't work": it simply isn't as effective at getting people moving to the mental model you're prescribing. People would have mostly trucked as they have.
Except people not wanting to do that mental shift was largely why they chose Next.js over a framework like Remix.
Choosing a default that breaks things (forcing npm packages to label their components...) was way too heavy handed considering the tenuous nature of RSC as a whole with its single implementation at this point.
Making client components default (as they have been since the dawn of React) and saying something like "server only" would have done the trick.
But with the directive "use client" you hit the mental pathway that people have around SSR. It adds just enough friction to feel like you're missing out even though it's almost orthogonal to the concept of SSR.
The problem with the approach you’re suggesting is that it creates client-server waterfalls. Avoiding those is the entire point of the design — otherwise it’s dead on arrival.
Suppose that, as you say, client is default, and marking a component as server is opt-in. This means that in any given tree, a server component can appear in the middle and be rendered by a client component. That, in turn, means that any time that client component re-renders, the server component rendered by it need to refetch. But that server component may render another client component under it, which may render another server component (under the design you’re proposing). As a consequence, a simple state update in a client component somewhere can trigger an entire chain of repeated client/server waterfalls just to resolve the resulting tree. This is not a feasible design.
The way RSC solves this problem is by (1) starting the data flow from the server, and (2) ensuring that during rendering, the data always flows in one direction — from server to client. This restriction avoids the client/server network waterfalls I’ve described in the previous paragraph. But it does require that client is opt-in rather than server.
Let's be clear, the design I'm proposing makes no changes to which boundaries are allowed. It simply switches the default from shared to client. Nothing stops a given bundler from requiring a shared component where one is expected now.
What that compromise would have done however is caused significantly less adoption, because "out of sight, out of mind". Most people would not opt into shared/server since RSC is not providing enough value for them: They don't mind the waterfalls, they're stuck in their ways, and above all they highly value reactivity bring sprinkled everywhere since that's what they were all running away from in template based frameworks.
I think where we likely won't see eye to eye is if that was a fair decision to make. I think especially given the singular implementor, the React time should have left RSC as a default disabled and left the uphill battle to Vercel to convince developers to opt into RSC in their own bundler.
Forcing NPM packages to need to think about appending "use client" to be is the smoking gun that this was the wrong move.
The default is client components. You need to opt-in to server components by running a server that serves up your root component as a server component.
No, the default is shared. It's literally in the RFC.
That's why using any interactivity in a component default breaks until you add "use client". The alternative would have been to have state, a core concept of React, work correctly by default, and make server/shared components explicitly marked.
AFAIK: the initial stages of the project involved Vercel and Shopify [edit: and Gatsby]. these companies maintain frameworks and hosting solutions for them, which makes them good partners to work on full-stack features like this. notably, the convention ("use client") came about based on early feedback from Shopify.
the reason to work with framework authors first is that RSC requires a high degree of coordination/wiring across client code, server code, and the bundler. React itself only implements a couple of low-level primitives that need to be wired together by something like a framework to actually do anything useful
> expecting all third-party packages, React-related or not, to buy into the "use client" directive
AFAIK: non-react code has no reason to care about this directive. and on the react side, couldn't you make the same complaint about most breaking changes?
In short, it's because Vercel invested engineer-years into piloting RSCs as part of a production framework and making Next the guinea pig. Next wasn't actually the first framework to try RSCs - Hydrogen (Shopify) and Gatsby both tried early versions of it and provided feedback, but Next is the first to implement it to the point that it can be considered stable.
The long-term goal is that RSCs aren't a Next-only concept - for example the Remix team said that they wouldn't implement them until they became more stable (https://twitter.com/ryanflorence/status/1678416472010260480), but are working on it now (https://twitter.com/ryanflorence/status/1697253955376722092). But the React team has always historically favoured trying new features in production to iterate on the API (this happened a lot internally at Meta), and this was an opportunity to do that.
"use client" is more of a bundler feature. It doesn't propagate to components per se, it affects the import tree. You can think of "use client" as a directive that says: the entire module graph below gets shipped to the client bundle.
I don't understand how this is acceptable to the React user community, that only Vercel gets to be in this privileged position. Why did they not include other companies, or the users themselves, in the discussion and development of this feature.
> Since Server Components are a new React feature, third-party packages and providers in the ecosystem are just beginning to add the "use client" directive to components that use client-only features like useState, useEffect, and createContext.
> Today, many components from npm packages that use client-only features do not yet have the directive. These third-party components will work as expected within Client Components since they have the "use client" directive, but they won't work within Server Components.
The arrogance of expecting all third-party packages, React-related or not, to buy into the "use client" directive. A humbler approach would have been a "use server" directive to opt-in to this behavior, instead of expecting the entire rest of the ecosystem to adapt to it.