Как работает React.lazy?
React.lazy позволяет загружать компоненты лениво, только тогда, когда они действительно нужны. Это особенно полезно, когда ваш код включает в себя крупные библиотеки или части, которые не используются сразу.
Пример:
import React, { Suspense } from 'react';
// Лениво загружаем компонент
const LazyComponent = React.lazy(() => import('./LazyComponent'));
export const App: React.FC = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
};
В этом примере LazyComponent будет загружен динамически во время рендеринга. Пока компонент загружается, React показывает fallback загрузочный индикатор.
Теперь давайте разберёмся, как к этому всему добавить типизацию.
Типизация компонентов для React.lazy
1. Базовый пример типизации
Когда мы используем React.lazy, важно, чтобы типы загружаемого компонента совпадали с тем, что вы ожидаете в коде. Вот пример правильной типизации:
import React, { Suspense } from 'react';
// Интерфейс для пропсов компонента
interface LazyComponentProps {
title: string;
count: number;
}
// Лениво загружаем компонент, определяя его тип
const LazyComponent = React.lazy<React.FC<LazyComponentProps>>(() => import('./LazyComponent'));
export const App: React.FC = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent title="Hello World" count={42} />
</Suspense>
);
};
Здесь мы явно указываем React.lazy<React.FC<LazyComponentProps>>, чтобы типизировать компонент. Если кто-то попробует передать пропсы, которые не соответствуют LazyComponentProps, TypeScript сразу предупредит об ошибке.
2. Типизация с использованием default export
Очень часто компоненты, созданные для ленивой загрузки, экспортируются как default. В этом случае важно убедиться, что они обладают требуемым типом:
// LazyComponent.tsx
import React from 'react';
interface LazyComponentProps {
message: string;
}
const LazyComponent: React.FC<LazyComponentProps> = ({ message }) => {
return <div>{message}</div>;
};
export default LazyComponent;
// App.tsx
import React, { Suspense } from 'react';
// Типизируем ленивую загрузку компонента
const LazyComponent = React.lazy(() => import('./LazyComponent'));
export const App: React.FC = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent message="Dynamic Component Loaded!" />
</Suspense>
);
};
Здесь TypeScript автоматически определяет тип через экспорт по умолчанию, но при необходимости вы можете уточнить его явно.
3. Типизация с использованием named exports
Если ваш компонент экспортируется по имени named export, вам придётся указать точный экспорт при использовании React.lazy:
// LazyComponent.tsx
import React from 'react';
interface LazyComponentProps {
title: string;
}
export const LazyComponent: React.FC<LazyComponentProps> = ({ title }) => {
return <h1>{title}</h1>;
};
// App.tsx
import React, { Suspense } from 'react';
// Ленивый импорт конкретного компонента
const LazyComponent = React.lazy(() =>
import('./LazyComponent').then((module) => ({ default: module.LazyComponent }))
);
export const App: React.FC = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent title="Named Export Component" />
</Suspense>
);
};
Здесь требуется указать default в объекте, так как React.lazy ожидает, что загружаемый модуль экспортирует компонент по умолчанию.
4. Обработка ошибок при загрузке
При работе с ленивой загрузкой возможны ошибки загрузки компонентов, например, когда файл не найден или сервер вернул ошибку. В таких случаях важно, чтобы ваше приложение корректно обрабатывало эти ситуации.
import React, { Suspense, lazy } from 'react';
// Типизируем лениво загружаемый компонент
const LazyComponent = lazy(() => import('./LazyComponent').catch((error) => {
console.error('Error loading LazyComponent:', error);
return { default: () => <div>Error loading component</div> };
}));
export const App: React.FC = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
};
В этом примере мы добавили обработку ошибок внутри React.lazy. Если компонент не может быть загружен, вместо него будет показан компонент с сообщением об ошибке.
5. Упрощение типизации с фабриками компонентов
Если вам приходится много работать с ленивыми компонентами, можно создать вспомогательную функцию для упрощения типизации:
import React from 'react';
// Фабрика для ленивой загрузки компонентов
const lazyWithProps = <P extends object>(factory: () => Promise<{ default: React.ComponentType<P> }>) =>
React.lazy(factory);
interface LazyComponentProps {
text: string;
}
const LazyComponent = lazyWithProps<LazyComponentProps>(() => import('./LazyComponent'));
export const App: React.FC = () => {
return (
<React.Suspense fallback={<div>Loading...</div>}>
<LazyComponent text="Hello from factory!" />
</React.Suspense>
);
};
Эта фабрика помогает избежать повторения кода и обеспечивает строгую типизацию для всех ленивых компонентов.
Частые ошибки
- Ошибка типов пропсов: если указать неправильные пропсы для ленивого компонента, TypeScript сразу выдаст предупреждение, но без типизации вы можете получить ошибку только в момент рендеринга.
- Отсутствие
fallback: не забывайте всегда добавлятьfallbackвSuspense, чтобы приложение не зависало в случае долгой загрузки. - Неправильный импорт: для
named exportsпомните, что модуль должен быть преобразован в объект сdefault.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ