<AsyncBoundary />
Handles loading and error conditions of Suspense.
In React 18, this will create a concurrent split, and in 16 and 17 it will show loading fallbacks. If there is an irrecoverable error, it will show an error fallback.
Learn more about boundary placement by learning how to co-locate data dependencies
Usage
Place AsyncBoundary
at or above navigational boundaries like pages, routes, or modals.
- React Router
- NextJS
- Expo
- Antd Modal
import { AsyncBoundary } from '@data-client/react';
import { Outlet } from 'react-router';
export default function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<section>
<AsyncBoundary>
<Outlet />
</AsyncBoundary>
</section>
</div>
);
}
import { AsyncBoundary } from '@data-client/react';
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div>
<h1>Dashboard</h1>
<section>
<AsyncBoundary>{children}</AsyncBoundary>
</section>
</div>
);
}
import { AsyncBoundary } from '@data-client/react';
import { Slot } from 'expo-router';
export default function DashboardLayout() {
return (
<ParallaxScrollView
headerBackgroundColor={{ light: '#A1CEDC', dark: '#1D3D47' }}
headerImage={
<Image
source={require('@/assets/images/my-logo.png')}
style={styles.logo}
/>
}
>
<AsyncBoundary>
<Slot />
</AsyncBoundary>
</ParallaxScrollView>
);
}
import { AsyncBoundary } from '@data-client/react';
import { Button, Modal } from 'antd';
export default function ModalOpen() {
return (
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal title="Basic Modal" open={isModalOpen} onOk={handleOk} onCancel={handleCancel}>
<AsyncBoundary>
<MyModalBody />
</AsyncBoundary>
</Modal>
</>
);
}
Then useSuspense() in the components that render the data. Any errors or loading state
from any descendant of the <AsyncBoundary />
will be rendered at the <AsyncBoundary />
. This consolidation
of fallback UI improves performance and usability.
function SuspendingComponent() {
const data = useSuspense(getMyThing);
return <div>{data.text}</div>;
}
Props
interface BoundaryProps {
children: React.ReactNode;
fallback?: React.ReactNode;
errorClassName?: string;
errorComponent?: React.ComponentType<{
error: NetworkError;
resetErrorBoundary: () => void;
className?: string;
}>;
listen?: (resetListener: () => void) => () => void;
}
fallback
Any renderable (React Node) element to show when loading
errorComponent
Component to handle caught errors
Custom fallback example
import React from 'react';
import { DataProvider, AsyncBoundary } from '@data-client/react';
function ErrorPage({
error,
className,
resetErrorBoundary,
}: {
error: Error;
resetErrorBoundary: () => void;
className?: string;
}) {
return (
<pre role="alert" className={className}>
{error.message} <button onClick={resetErrorBoundary}>Reset</button>
</pre>
);
}
export default function App() {
return (
<DataProvider>
<AsyncBoundary fallback="loading" errorComponent={ErrorPage}>
<Router />
</AsyncBoundary>
</DataProvider>
);
}
errorClassName
className
to forward to errorComponent
listen
Subscription handler to reset error state on events like URL location changes. This is great for placing a boundary to wrap routing components.
An example using Anansi Router, which uses history subscription.
import { useController } from '@anansi/router';
import { AsyncBoundary } from '@data-client/react';
function App() {
const { history } = useController();
return (
<div>
<nav>
<Link name="Home">Coin App</Link>
</nav>
<main>
<AsyncBoundary listen={history.listen}>
<MatchedRoute index={0} />
</AsyncBoundary>
</main>
</div>
);
}