The Await component provides a declarative way to handle asynchronous operations in React, managing loading states, errors, and successful data resolution with a clean, composable API.
When to Use
Display loading states while data is being fetched
Handle errors from async operations gracefully
Show different UI based on promise resolution state
Avoid manual promise handling with useState and useEffect
Integrate with React Suspense and Error Boundaries automatically
Basic Usage
Render Prop Pattern
Slot-based Pattern
import { Await } from "@zayne-labs/ui-react/common/await" ;
const fetchUser = async ( id : string ) => {
const response = await fetch ( `/api/users/ ${ id } ` );
return response . json ();
};
function UserProfile ({ userId } : { userId : string }) {
const userPromise = fetchUser ( userId );
return (
< Await.Root promise = { userPromise } >
{ ( user ) => (
< div >
< h1 > { user . name } </ h1 >
< p > { user . email } </ p >
</ div >
) }
</ Await.Root >
);
}
Component API
Await.Root
The root component that manages the promise lifecycle.
The promise to await and resolve
children
React.ReactNode | ((result: TValue) => React.ReactNode)
required
Content to render on success. Can be a render function receiving the resolved value
Fallback UI to show while the promise is pending (passed to Suspense)
errorFallback
React.ReactNode | ((props: ErrorFallbackProps) => React.ReactNode)
Fallback UI to show when the promise rejects (passed to ErrorBoundary)
Whether to wrap children with React Suspense
Whether to wrap children with ErrorBoundary
Merge props into the child element instead of rendering a wrapper
Await.Success
Renders content when the promise resolves successfully.
children
React.ReactNode | ((result: TValue) => React.ReactNode)
required
Content to render. Can be a render function receiving the resolved value
Await.Error
Renders content when the promise rejects.
children
React.ReactNode | ((context: ErrorBoundaryContext) => React.ReactNode)
required
Content to render on error. Render function receives error and resetErrorBoundary
Merge props into the child element
Await.Pending
Renders content while the promise is pending.
Advanced Examples
Using Inline Props
import { Await } from "@zayne-labs/ui-react/common/await" ;
function DataDisplay () {
const dataPromise = fetchData ();
return (
< Await.Root
promise = { dataPromise }
fallback = { < Spinner /> }
errorFallback = { ({ error , resetErrorBoundary }) => (
< div >
< p > Failed to load: { error . message } </ p >
< button onClick = { resetErrorBoundary } > Retry </ button >
</ div >
) }
>
{ ( data ) => < pre > { JSON . stringify ( data , null , 2 ) } </ pre > }
</ Await.Root >
);
}
Disabling Suspense/ErrorBoundary
import { Await } from "@zayne-labs/ui-react/common/await" ;
import { Suspense } from "react" ;
import { ErrorBoundary } from "@zayne-labs/ui-react/common/await" ;
function CustomBoundaries () {
const promise = fetchData ();
return (
< ErrorBoundary fallback = { ( props ) => < CustomError { ... props } /> } >
< Suspense fallback = { < CustomLoader /> } >
< Await.Root
promise = { promise }
withSuspense = { false }
withErrorBoundary = { false }
>
{ ( data ) => < div > { data . content } </ div > }
</ Await.Root >
</ Suspense >
</ ErrorBoundary >
);
}
Using asChild for Prop Merging
import { Await } from "@zayne-labs/ui-react/common/await" ;
function StyledError () {
const promise = fetchData ();
return (
< Await.Root promise = { promise } >
< Await.Error asChild >
{ ({ error , resetErrorBoundary }) => (
< div className = "error-container" role = "alert" >
< h2 > Something went wrong </ h2 >
< p > { error . message } </ p >
< button onClick = { resetErrorBoundary } > Try Again </ button >
</ div >
) }
</ Await.Error >
< Await.Success >
{ ( data ) => < div > { data . content } </ div > }
</ Await.Success >
</ Await.Root >
);
}
Comparison to Native Patterns
Traditional Approach
function UserProfile ({ userId } : { userId : string }) {
const [ user , setUser ] = useState ( null );
const [ loading , setLoading ] = useState ( true );
const [ error , setError ] = useState ( null );
useEffect (() => {
setLoading ( true );
fetchUser ( userId )
. then ( setUser )
. catch ( setError )
. finally (() => setLoading ( false ));
}, [ userId ]);
if ( loading ) return < div > Loading... </ div > ;
if ( error ) return < div > Error: { error . message } </ div > ;
if ( ! user ) return null ;
return (
< div >
< h1 > { user . name } </ h1 >
< p > { user . email } </ p >
</ div >
);
}
With Await Component
function UserProfile ({ userId } : { userId : string }) {
const userPromise = fetchUser ( userId );
return (
< Await.Root promise = { userPromise } fallback = { < div > Loading... </ div > } >
{ ( user ) => (
< div >
< h1 > { user . name } </ h1 >
< p > { user . email } </ p >
</ div >
) }
</ Await.Root >
);
}
The Await component uses React’s use hook internally to unwrap promises, automatically integrating with Suspense boundaries for optimal loading states.
Common Use Cases
Data Fetching with Loading States
function ProductList () {
const productsPromise = fetch ( "/api/products" ). then (( r ) => r . json ());
return (
< Await.Root promise = { productsPromise } >
< Await.Pending >
< div className = "grid gap-4" >
{ Array . from ({ length: 6 }). map (( _ , i ) => (
< ProductSkeleton key = { i } />
)) }
</ div >
</ Await.Pending >
< Await.Success >
{ ( products ) => (
< div className = "grid gap-4" >
{ products . map (( product ) => (
< ProductCard key = { product . id } product = { product } />
)) }
</ div >
) }
</ Await.Success >
</ Await.Root >
);
}
Graceful Error Handling
function UserSettings () {
const settingsPromise = fetchSettings ();
return (
< Await.Root promise = { settingsPromise } >
< Await.Error >
{ ({ error , resetErrorBoundary }) => (
< div className = "error-state" >
< h2 > Failed to load settings </ h2 >
< p > { error . message } </ p >
< div className = "actions" >
< button onClick = { resetErrorBoundary } > Retry </ button >
< button onClick = { () => window . location . reload () } >
Reload Page
</ button >
</ div >
</ div >
) }
</ Await.Error >
< Await.Success >
{ ( settings ) => < SettingsForm settings = { settings } /> }
</ Await.Success >
</ Await.Root >
);
}