I’m excited about React Server Components. In this post, I will summarize the benefits and limitations in a few quick points.
For more details, check out the Facebook team’s announcement video.
The Big Idea
Render React components in one of 3 ways:
- On the server – Use a .server.js extension.
- On the client – Use a .client extension.
- On both client and server – Use a plain .js extension. This is called a shared component.
So you can think of your React app as a single tree that’s a mix of client, server, and shared components.
This currently works with Webpack and Next.js. Parcel support is coming soon.
It’s still in research and development, but being used at Facebook in prod. Initially will be consumable solely via frameworks (since need server and routing opinions to pull this off). Longer term, no framework required.
Related React IO Packages
These small wrapper packages teach React how to cache results.
- react-fetch – Wraps fetch. Runs on client and server.
- react-fs – Wraps Node’s fs module for reading files.
- react-pg – Call a PostgreSQL DB from a React server component
The community is expected to contribute other similar packages soon.
- Sever rendering increases performance by reducing time to first paint and reducing the amount of JS sent to (and thus parsed by) the client. Server components have zero effect on bundle size. FB is seeing an 29% reduction in bundle size.
- Eliminates data fetch “waterfalls” by quickly fetching data from multiple endpoints on the server. Fetching on the server avoids multiple HTTP round-trips when one API call depends upon another.
- Automatic code splitting. The client only receives dependencies that are used by client components. For example, if using a large date package like date-fns on only server components, then date-fns isn’t even in the client bundle! (you can check the sources tab to see what webpack is sending down)
- When passing JSX to a client component as a prop/children, the JSX is rendered on the server. (perf win)
- If a server component doesn’t end up using an imported dependency, (for example, a child component is only rendered in some cases), then the unused child component code isn’t sent to the client.
- Shared components are downloaded on demand. So if rendered on the server first, the shared component is downloaded on demand when the client actually needs it.
- Server components aren’t sent from the server in HTML format. Instead, they’re sent over the wire in a special format that can be streamed down to the client and woven into the existing app. So they’re compatible with Suspense.
- Unlike traditional server-side rendering, client-side state is fully maintained when new server-side components are fetched. That’s the benefit of their unique over-the-wire format.
- Can change data fetching paradigms in server components over time without impacting any other code (for example, call db directly vs call API vs read file)
- Can choose the right component paradigm for each use case. Have heavy dependencies that are read once such as an article or a heavy date library? Use a server component. Need interactivity? Use a client component. And since there’s no technological wall, the code can be shared. So most components will likely be shared components.
- Opt-in. Current way of working in React isn’t impacted or going away.
- You don’t have to choose between maintainability and performance. You can have both. Render on the server for extra performance. But you need no new paradigm or duplicated client-server code to pull it off.
- Can’t have any interactivity in server components. So can’t have state or event listeners. Solution? Put interactivity in a client component (Server components can import client components).
- Can only pass serializable props from server to client components. (so can’t pass a func as a prop from server to client because functions aren’t serializable to JSON). React will throw an error if you try.
The Next.js team is collaborating with the React team. So they’re the first framework embracing this emerging tech.