defineAsyncComponent
这是对 Vue defineAsyncComponent 的适配实现,用于在 React 中创建异步加载的组件。
说明
异步组件允许你将组件代码分割成独立的包,在需要时才加载。这对于优化大型应用的初始加载时间特别有用。
基本使用
函数形式
tsx
const AsyncComponent = defineAsyncComponent(() => import('./MyComponent'));
function App() {
return <AsyncComponent />;
}配置对象形式
tsx
const AsyncComponent = defineAsyncComponent({
loader: () => import('./MyComponent'),
loadingComponent: LoadingSpinner,
errorComponent: ErrorDisplay,
delay: 200,
timeout: 5000,
});配置选项
loader
- 类型:
() => Promise<Component | { default: Component }> - 必需: 是
- 说明: 异步加载组件的函数。可以返回组件本身或包含
default属性的 ES 模块对象。
loadingComponent
- 类型:
ComponentType<any> - 默认:
undefined - 说明: 组件加载过程中显示的加载组件。
errorComponent
- 类型:
ComponentType<{ error: Error }> - 默认:
undefined - 说明: 加载失败时显示的错误组件。接收
error属性。
delay
- 类型:
number - 默认:
200 - 说明: 延迟显示加载组件的时间(毫秒)。如果组件在延迟时间内加载完成,则不会显示加载组件。
timeout
- 类型:
number - 默认:
undefined - 说明: 加载超时时间(毫秒)。超过指定时间未加载完成将触发错误。
suspensible
- 类型:
boolean - 默认:
true - 说明: 是否可挂起。当组件在运行时 Suspense 边界内时,将使用 React Suspense 机制。
onError
- 类型:
(error: Error, retry: () => void, fail: () => void, attempts: number) => any - 默认:
undefined - 说明: 错误处理回调函数。可以自定义重试逻辑。
hydrate
- 类型:
(...args: any[]) => any - 默认:
undefined - 说明: ⚠️ 当前在 React 运行时中未实现,开发环境下会显示警告。
高级用法
自定义错误处理
tsx
const AsyncComponent = defineAsyncComponent({
loader: () => import('./MyComponent'),
onError: (error, retry, fail, attempts) => {
console.error(`加载失败,已尝试 ${attempts} 次`, error);
if (attempts < 3) {
// 重试加载
retry();
} else {
// 放弃加载
fail();
}
},
errorComponent: ({ error }) => (
<div>
<h3>加载失败</h3>
<p>{error.message}</p>
<button onClick={() => window.location.reload()}>刷新页面</button>
</div>
),
});延迟显示加载状态
tsx
const AsyncComponent = defineAsyncComponent({
loader: () => import('./HeavyComponent'),
loadingComponent: () => <Spinner size="large" />,
delay: 300, // 300ms 内加载完成则不显示加载状态
});超时处理
tsx
const AsyncComponent = defineAsyncComponent({
loader: () => import('./SlowComponent'),
timeout: 10000, // 10秒超时
errorComponent: ({ error }) => <Alert type="error" message={`加载超时: ${error.message}`} />,
});与 Suspense 集成
tsx
import { Suspense } from '@vureact/runtime-core';
function App() {
const AsyncComponent = defineAsyncComponent(() => import('./LazyComponent'));
return (
<Suspense fallback={<LoadingScreen />}>
<AsyncComponent />
</Suspense>
);
}禁用 Suspense
tsx
const AsyncComponent = defineAsyncComponent({
loader: () => import('./MyComponent'),
loadingComponent: LoadingIndicator,
suspensible: false, // 禁用 Suspense,使用本地加载流程
});特性说明
请求去重
当多个相同异步组件同时渲染时,加载请求会被去重,避免重复加载。
tsx
// 只会发起一次加载请求
<>
<AsyncComponent />
<AsyncComponent />
<AsyncComponent />
</>组件缓存
已加载的组件会被缓存,组件卸载后重新挂载时不会重新加载。
竞态条件处理
当新的加载请求发起时,旧的 pending 请求会被正确处理,避免状态混乱。
ES 模块支持
自动处理 ES 模块格式(包含 default 属性)和普通组件格式。
tsx
// 两种格式都支持
defineAsyncComponent(() => import('./Component')); // { default: Component }
defineAsyncComponent(() => Promise.resolve(Component)); // Component注意事项
hydrate 选项: 当前在 React 运行时中未实现,开发环境下会显示警告。
Suspense 边界: 当
suspensible=true且组件在运行时 Suspense 边界内时,会使用 React Suspense 机制。否则使用本地加载/错误流程。错误边界: 建议将异步组件包裹在错误边界中,以处理未捕获的加载错误。
TypeScript 支持: 完整的 TypeScript 类型定义,支持智能提示。
性能优化: 对于频繁切换的异步组件,考虑使用
KeepAlive组件进行缓存。
API
ts
function defineAsyncComponent<T extends ComponentType<any>>(
source: () => Promise<T | { default: T }>,
): T;
function defineAsyncComponent<T extends ComponentType<any>>(source: {
loader: () => Promise<T | { default: T }>;
loadingComponent?: ComponentType<any>;
errorComponent?: ComponentType<{ error: Error }>;
delay?: number;
timeout?: number;
suspensible?: boolean;
hydrate?: (...args: any[]) => any;
onError?: (error: Error, retry: () => void, fail: () => void, attempts: number) => any;
}): T;