> ## Content Index
> Fetch the complete content index at: https://madewithlove.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# Crossing boundaries: Passing server data to client components in React
- URL: https://madewithlove.com/blog/crossing-boundaries-passing-server-data-to-client-components-in-react/
- Published: 2024-09-30T07:44:45.000Z
- Updated: 2025-02-25T08:11:57.000Z
- Description: Learn how to optimize performance by fetching data server-side without blocking the page render. This guide explores passing promises to React client components and resolving them asynchronously using Suspense, ensuring a smoother, faster user experience.
- Author: Geoffrey Dhuyvetters
- Tags: Engineering, Code quality, Ideas, Tutorials, JavaScript, React, Frontend

When developing applications, it’s common to encounter components that require substantial client-side functionality, making them ideal candidates for **React client components**. In this example, we’re working on a dashboard page. For this, we need to fetch data for a `UserProfile` component (a client-side component) while aiming to avoid the overhead of creating a separate API endpoint.

## Fetch the data on the server

One way to tackle this is to fetch the data in the **server** component and pass it down to the **client** component. Below is a basic implementation that does just that:

```javascript
import { Suspense } from 'react';
import { getUser } from './actions/getUser';

export default async function Dashboard() {
  const user = await getUser();
  
  return (
    <p>
      <BigUIChunk />
      <UserProfile user={user} />
    </p>
  );
}
```

This approach works as expected; however, this introduces a significant issue: the full page render is **blocked** until the `getUser` promise is resolved.

### The issue with blocking

Blocking the entire page render while waiting for a promise can lead to a **subpar** experience. The user sees nothing until the server fetch is complete. This could be frustrating, depending on network conditions or backend performance. Users expect dashboards to load **immediately**, even if some content needs to be fetched in the background.

## A non-blocking alternative: Pass the promise to the client

To improve the user experience, we can opt for a **non-blocking** approach. Instead of resolving the promise on the server, we can pass the unresolved promise down to the client and let it resolve there. This way, the page can **render immediately**, and the data will be loaded asynchronously.

Here’s how we implement this approach:

```javascript
import { Suspense } from 'react';
import { getUser } from './actions/getUser';

export default function Dashboard() {
  
  // Don't resolve the promise
  const getUserPromise = getUser();
  
  return (
    <p>
      <BigUIChunk />
      <Suspense fallback={<p>loading...</p>}>
        <UserProfile getUserPromise={getUserPromise} />
      </Suspense>
    </p>
  );
}
```

In this version, we wrap the `UserProfile` component in [React’s Suspense](https://react.dev/reference/react/Suspense) component. This allows us to provide a fallback UI, such as a spinner or [loading skeleton](https://ui.shadcn.com/docs/components/skeleton), while the promise is resolved. This improves perceived performance as the user immediately sees part of the page load while the rest of the content is fetched in the background.

### Resolving the promise in the component

Once the **promise** reaches the client-side component, we can **resolve** it using React’s [use hook](https://react.dev/reference/react/use). This approach ensures the user data is fetched and used as soon as it becomes available. Here’s how we would handle this in the client component:

```javascript
"use client";

import { use } from 'react';

export default function UserProfile({ getUserPromise }) {
  const user = use(getUserPromise);
  
  return <pre>{JSON.stringify(user, null, 2)}</pre>;
}
```

**In Conclusion**, passing down promises to client components and resolving them using the use hook gives us a flexible way to handle asynchronous data without blocking the initial render. This pattern ensures a smoother user experience on pages where users expect fast, immediate interaction.

**Also read:**

- [Handling data mutations in client components](https://madewithlove.com/blog/crossing-boundaries-handling-data-mutations-in-client-components/)
- [Instant feedback on useOptimistic hook in React](https://madewithlove.com/blog/instant-feedback-using-the-useoptimistic-hook-in-react/)