React Server Components: My Aha Moment
For the longest time, I looked at React Server Components (RSCs) with a mix of skepticism and fatigue. Another paradigm shift? Really? We just got used to hooks.
I kept reading the docs, watching the talks, and nodding along to terms like "zero bundle size" and "direct backend access." But it didn't really click until I had to build a dashboard that needed to aggregate data from three different crappy APIs.
In the old days (which was like, two years ago), my mental model was:
- Show a spinner.
- Fire off three
useEffectfetches. - Handle the loading states, the error states, and the inevitable waterfall if one request depended on another.
- Finally render the UI.
The code was messy, full of isLoading flags, and frankly, annoying to maintain.
Then I tried it with an RSC.
// This runs ON THE SERVER. Mind blown.
export default async function Dashboard() {
const [users, stats, alerts] = await Promise.all([
fetchUsers(),
fetchStats(),
fetchAlerts(),
]);
return (
<div className="grid">
<UserWidget data={users} />
<StatsWidget data={stats} />
<AlertsWidget data={alerts} />
</div>
);
}That was it. The aha moment.
I wasn't managing state. I wasn't managing effects. I was just... writing a function that returned UI. It felt like writing PHP back in the day, but with the component model and ecosystem of React.
The beauty isn't just in the reduced client-side JavaScript (though that's nice). The beauty is in the simplified mental model. The server does the heavy lifting, gathers the data, and hands the client exactly what it needs to render—nothing more, nothing less.
It took me a while to stop reaching for useState by default, but once you embrace the server-first mindset, it's hard to go back to the spinner life.