Using ‘use’ to stream deferred content

In the constant bid to improve page performance, I discovered use, an API recently shipped by React, and made available in Next.js. You’d be forgiven for not immediately understanding its function, given the oh-so-descriptive name.
use lets you …


This content originally appeared on Trys Mudford's Blog and was authored by Trys Mudford's Blog

In the constant bid to improve page performance, I discovered use, an API recently shipped by React, and made available in Next.js. You’d be forgiven for not immediately understanding its function, given the oh-so-descriptive name.

use lets you read the value of a promise (or context if you’re that way inclined). It feels like a bit of syntactic sugar, to avoid writing .then() or await within your component, but I’m sure there’s more to it than that.

When is it useful?

Take this carousel. Pretty standard stuff at the end of a product page. Definitely shouldn’t be render-blocking, and a prime candidate for deferred loading. We could move the data request into a client-side handler and call useEffect to fetch the data on the client, but finding ways to avoid useEffect becomes a source of personal pride once you’ve worked on a React project for any length of time. This approach has to wait for the whole page to hydrate before it can get to work loading the data.

Instead, we can still begin fetching the data on the server, but combine <Suspense> and use to handle the loading state before resolving it on the client.

What does it look like?

Before:

export default async function Page() {
	// Wait for the data to load
    const vehicles = await getVehiclesFromDB();

    return {
        <>
            // ... render the page
            <SimilarVehicles vehicles={vehicles} />
        </>
    }
}

export const SimilarVehicles: React.FC<{
    vehicles: VehiclePreview[];
}> = ({ vehicles }) => {
    return (
        <section className={cx(styles.section)}>
            {vehicles.map((vehicle) => (
                <VehicleCard
                    key={vehicle.vehicleId}
                    vehicle={vehicle}
                />
            ))}
        </section>
    );
};

After:

export default async function Page() {
    // Crack on rendering the page
    const vehiclesPromise = getVehiclesFromDB();

    return {
        <>
            // ... render the page
            <Suspense fallback={<LoadingState />}>
                <SimilarVehicles vehiclesPromise={vehiclesPromise} />
            </Suspense>
        </>
    }
}

export const SimilarVehicles: React.FC<{
    vehiclesPromise: Promise<VehiclePreview[]>;
}> = ({ vehiclesPromise }) => {
    // Resolve the promise
    const vehicles = use(vehiclesPromise);

    return (
        <section className={cx(styles.section)}>
            {vehicles.map((vehicle) => (
                <VehicleCard
                    key={vehicle.vehicleId}
                    vehicle={vehicle}
                />
            ))}
        </section>
    );
};

How does it work?

By continuing to call the vehicles database from the server, we’ve kept our precious server-side secrets safe. But by omitting await, we can crack on with streaming the page to the user much quicker than before.

React pops our fallback component in place, and continues to stream the page in the background until the database call resolves. At that point, the page connection closes and the component inside <Suspense> is rendered. use converts the promise over to our intended data format, and the component renders as expected.

You can even use ErrorBoundary to handle promise failures. Pretty neat.

Does it work without JS?

Sadly not. React needs JS at runtime to swap out the loading content with the deferred content. Non-JS users will be left with the loading component for infinity. So this isn’t appropriate for core user journey functionality, or spider-friendly content.


This content originally appeared on Trys Mudford's Blog and was authored by Trys Mudford's Blog


Print Share Comment Cite Upload Translate Updates
APA

Trys Mudford's Blog | Sciencx (2024-08-30T00:00:00+00:00) Using ‘use’ to stream deferred content. Retrieved from https://www.scien.cx/2024/08/30/using-use-to-stream-deferred-content/

MLA
" » Using ‘use’ to stream deferred content." Trys Mudford's Blog | Sciencx - Friday August 30, 2024, https://www.scien.cx/2024/08/30/using-use-to-stream-deferred-content/
HARVARD
Trys Mudford's Blog | Sciencx Friday August 30, 2024 » Using ‘use’ to stream deferred content., viewed ,<https://www.scien.cx/2024/08/30/using-use-to-stream-deferred-content/>
VANCOUVER
Trys Mudford's Blog | Sciencx - » Using ‘use’ to stream deferred content. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/08/30/using-use-to-stream-deferred-content/
CHICAGO
" » Using ‘use’ to stream deferred content." Trys Mudford's Blog | Sciencx - Accessed . https://www.scien.cx/2024/08/30/using-use-to-stream-deferred-content/
IEEE
" » Using ‘use’ to stream deferred content." Trys Mudford's Blog | Sciencx [Online]. Available: https://www.scien.cx/2024/08/30/using-use-to-stream-deferred-content/. [Accessed: ]
rf:citation
» Using ‘use’ to stream deferred content | Trys Mudford's Blog | Sciencx | https://www.scien.cx/2024/08/30/using-use-to-stream-deferred-content/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.