<AsyncBoundary />
处理 Suspense 的加载与错误状态。
在 React 18 中,它会创建一个并发拆分;在 16 和 17 中,它会显示加载 fallback。如果出现无法恢复的错误,它会显示错误 fallback。
提示
通过学习如何就近声明数据依赖,进一步了解边界应该放在哪里
用法
将 AsyncBoundary 放在页面、路由或模态框等导航边界处或其上方。
- React Router
- NextJS
- Expo
- Antd Modal
Dashboard.tsx
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>
);
}
app/dashboard/layout.tsx
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>
);
}
app/dashboard/_layout.tsx
import { AsyncBoundary } from '@data-client/react';
import { Slot } from 'expo-router';
import { Image, StyleSheet } from 'react-native';
import ParallaxScrollView from '@/components/ParallaxScrollView';
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>
);
}
const styles = StyleSheet.create({
logo: { height: 178, width: 290 },
});
ModalOpen.tsx
import { AsyncBoundary } from '@data-client/react';
import { useState } from 'react';
import { Button, Modal } from 'antd';
import MyModalBody from './MyModalBody';
export default function ModalOpen() {
const [isModalOpen, setIsModalOpen] = useState(false);
const showModal = () => setIsModalOpen(true);
const handleOk = () => setIsModalOpen(false);
const handleCancel = () => setIsModalOpen(false);
return (
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal title="Basic Modal" open={isModalOpen} onOk={handleOk} onCancel={handleCancel}>
<AsyncBoundary>
<MyModalBody />
</AsyncBoundary>
</Modal>
</>
);
}
然后在渲染数据的组件中使用 useSuspense()。<AsyncBoundary /> 的任何后代产生的错误或加载状态都会在 <AsyncBoundary /> 处渲染。这种对 fallback UI 的整合可以提升性能和可用性。
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
加载时显示的任意可渲染(React Node)元素
errorComponent
用于处理捕获到的错误的组件
自定义 fallback 示例
import React from 'react';
import { DataProvider, AsyncBoundary } from '@data-client/react';
import Router from './Router';
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
转发给 errorComponent 的 className
listen
订阅处理函数,用于在 URL 位置变化等事件发生时重置错误状态。非常适合用边界包裹路由组件的场景。
下面是使用 Anansi Router 的示例,它使用了 history 订阅。
import { useRouter, Link, MatchedRoute } from '@anansi/router';
import { AsyncBoundary } from '@data-client/react';
function App() {
const { history } = useRouter();
return (
<div>
<nav>
<Link name="Home">Coin App</Link>
</nav>
<main>
<AsyncBoundary listen={history.listen}>
<MatchedRoute index={0} />
</AsyncBoundary>
</main>
</div>
);
}