The Await component in Remix simplifies handling the asynchronous data by managing loading, success, and error states. It enhances performance and user experience in modern React applications.
Avait Component in Remix
The Await component in Remix is a powerful tool used to handle asynchronous operations within your application's components. It allows developers to fetch data or perform other async tasks and render the results dynamically within the UI. This is particularly useful in modern web development, where applications frequently rely on APIs and data fetching to provide dynamic content.
Syntax:
<Await
resolve={dataPromise}
errorElement={<p>Something went wrong!</p>}
>
{(data) => <YourComponent data={data} />}
</Await>
Props:
- resolve: The promise to be resolved.
- errorElement: Component to render in case of an error.
- children: A function that receives the resolved data.
Returns:
The Await component returns the resolved data or an error element if the promise fails.
There are several ways to utilize the Await component in Remix:
Table of Content
Key Concepts
- Suspense: A React component that blocks rendering until a promise resolves.
- Await: A component in Remix which uses Suspense under the hood, to provide better control over loading states.
- Optimistic UI: Technique in which the UI shows some temporary placeholder or assumed data until actual data is fetched.
Key Features
- Simplified Asynchronous Data Handling: The Await component makes it easier to handle async data directly within your JSX, reducing the need for complex state management and conditional rendering logic.
- Improved Performance: By deferring data loading until it's needed, the Await component helps improve the performance of your application and reduces the time to first render and enhancing overall user experience.
- Error Management: Await allows you to catch and display errors, ensuring that your application can handle the failures without breaking UI.
- Declarative Loading States: It provides a clean and declarative way to handle loading states and allows you to specify exactly what should be displayed while waiting loading data.
Project Setup
Step 1: Create the Project
Initialize a new Remix project named await-remix using the following command:
npx create-remix@latest await-remix
Step 2: Navigate to Your Project Directory
Move into the await-remix directory
cd await-remixStep 3: Install Dependencies
Ensure the following dependencies are included:
npm install
npm install @remix-run/react @remix-run/node @remix-run/serve @remix-run/router @remix-run/dev react react-dom
Choose a hosting option (e.g., "Remix App Server") and follow the prompts to complete the setup.

Check package.json: Ensure your package.json scripts and dependencies are correctly set up:
"scripts": {
"dev": "remix dev",
"build": "remix build",
"start": "remix-serve build"
},
"dependencies": {
"@remix-run/react": "^1.10.1",
"@remix-run/node": "^1.10.1",
"@remix-run/serve": "^1.10.1",
"@remix-run/router": "^1.10.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@remix-run/dev": "^1.10.1",
"typescript": "^5.0.0"
}
Folder Structure
Below is the project structure for Await Remix Project

Approach 1: Basic Usage
Handling simple promises and rendering results.
Syntax:
<Await resolve={fetchData()}>
{(data) => <p>{data.title}</p>}
</Await>
Steps:
- Create a function that returns a promise, e.g., a data fetch.
- Use the Await component and pass the promise to the resolve prop.
- Render the resolved data using the child function.
Example: This example uses the Await component in Remix to handle asynchronous data fetching, displaying a list of photo titles once the data resolves successfully.
// app/routes/_index.tsx
import { Await } from "@remix-run/react";
import { json, LoaderFunction, useLoaderData } from "@remix-run/node";
export let loader: LoaderFunction = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/photos");
const data = await res.json();
return json(data.slice(0, 10));
};
export default function Index() {
const data = useLoaderData();
return (
<div>
<h1>Photo List</h1>
<Await resolve={data}>
{(photos) =>
photos.map((photo) => <p key={photo.id}>{photo.title}</p>)
}
</Await>
</div>
);
}
// app/components/DataDisplay.tsx
import React from "react";
type DataDisplayProps = {
data: { id: number, title: string }[]
};
const DataDisplay: React.FC<DataDisplayProps> = ({ data }) => {
return (
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
);
};
export default DataDisplay;
Output:
Render a list of photo titles fetched from the API.

Approach 2: Error Handling
Providing custom error UI when promises fail.
Syntax:
<Await
resolve={fetchData()}
errorElement={<p>Could not fetch data</p>}
>
{(data) => <p>{data.title}</p>}
</Await>
Steps:
- Add an errorElement prop to handle failed promises.
- Test by passing an incorrect API URL.
Example: This example uses the Await component in Remix to handle asynchronous data fetching with error management, displaying either data or an error message based on the fetch operation's outcome.
// app/routes/_index.tsx
import { Await } from "@remix-run/react";
import { json, LoaderFunction } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import DataDisplay from "~/components/DataDisplay";
// Loader function with a deliberate error (wrong URL)
export let loader: LoaderFunction = async () => {
try {
const res = await fetch("https://invalid-url"); // Incorrect URL to simulate an error
if (!res.ok) throw new Error("Network response was not ok");
const data = await res.json();
return json(data.slice(0, 10));
} catch (error) {
throw new Response("Failed to fetch data", { status: 500 });
}
};
export default function Index() {
const data = useLoaderData();
return (
<div>
<h1>Photo List with Error Handling</h1>
<Await
resolve={data}
errorElement={
<p>Could not fetch data. Please try again later.</p>
}
>
{(photos) => <DataDisplay data={photos} />}
</Await>
</div>
);
}
Output:
Displays "Could not fetch data" if the promise fails.

Approach 3: Nested Await Components
Handling multiple asynchronous operations within nested components.
Syntax:
<Await resolve={firstPromise()}>
{(data1) => (
<Await resolve={secondPromise()}>
{(data2) => <p>{data1.title} and {data2.title}</p>}
</Await>
)}
</Await>
Steps:
- Nest Await components to handle multiple async operations.
- Pass data from each promise to subsequent Await components
Example:This example uses nested Await components in Remix to concurrently fetch and display photos and posts, managing multiple asynchronous operations efficiently in a single component.
// app/routes/_index.tsx
import { Await } from "@remix-run/react";
import { json, LoaderFunction } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import DataDisplay from "~/components/DataDisplay";
// Loader function to fetch two sets of data
export let loader: LoaderFunction = async () => {
const fetchPhotos = fetch("https://jsonplaceholder.typicode.com/photos");
const fetchPosts = fetch("https://jsonplaceholder.typicode.com/posts");
const [photosRes, postsRes] = await Promise.all([fetchPhotos, fetchPosts]);
const photos = await photosRes.json();
const posts = await postsRes.json();
return json({ photos: photos.slice(0, 5), posts: posts.slice(0, 5) });
};
export default function Index() {
const { photos, posts } = useLoaderData();
return (
<div>
<h1>Nested Await Example</h1>
<Await resolve={photos}>
{(photoData) => (
<Await resolve={posts}>
{(postData) => (
<div>
<h2>Photos</h2>
<DataDisplay data={photoData} />
<h2>Posts</h2>
<ul>
{postData.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
)}
</Await>
)}
</Await>
</div>
);
}
Output:
Displays combined data from two promises.

Step to Run the project:
To run the project use below command
npm run devConclusion
The Await component is your go-to tool inside Remix for dealing with asynchronous operations within your UI. Alone or combined with Suspense, it enhances the user experience with clear and responsive feedback during data fetching.