Как реализовать lazy loading экранов?

Lazy loading (ленивая загрузка) экранов в React Native позволяет откладывать загрузку компонентов до тех пор, пока они не понадобятся — например, до момента навигации на экран. Это значительно улучшает производительность приложения, особенно при большом числе экранов или тяжёлых компонентов. Основная идея — загружать экраны динамически, а не сразу при старте приложения.

В React Native ленивую загрузку чаще всего реализуют при помощи:

  • React.lazy() и Suspense (в RN Web и RN с React 18+)

  • асинхронного импорта экранов в навигации (например, с помощью createNativeStackNavigator из react-navigation)

  • кастомных механизмов, например, отображения заглушки (loader/spinner), пока не загрузится экран

Основы: что такое React.lazy()

React.lazy() — это функция из React, которая позволяет динамически загружать компоненты. Компонент загружается только тогда, когда он впервые используется.

const ProfileScreen = React.lazy(() => import('./screens/ProfileScreen'));

Чтобы использовать такие компоненты, нужно обернуть их в Suspense:

import { Suspense } from 'react';
&lt;Suspense fallback={<Text&gt;Загрузка...&lt;/Text&gt;}>
&lt;ProfileScreen /&gt;
&lt;/Suspense&gt;

Однако в React Native Suspense официально поддерживается только для некоторых случаев (например, при использовании React 18 и concurrent features). Поэтому в большинстве production-проектов применяют ленивую загрузку экранов в контексте react-navigation, без Suspense.

Lazy loading с react-navigation

1. Установка необходимых пакетов

npm install @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context react-native-gesture-handler

2. Базовая структура навигации с ленивой загрузкой

React Navigation автоматически поддерживает отложенную инициализацию экранов, если использовать getComponent.

App.js

import \* as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
export default function App() {
return (
&lt;NavigationContainer&gt;
&lt;Stack.Navigator&gt;
&lt;Stack.Screen name="Home" getComponent={() =&gt; require('./screens/HomeScreen').default} />
&lt;Stack.Screen name="Profile" getComponent={() =&gt; require('./screens/ProfileScreen').default} />
&lt;/Stack.Navigator&gt;
&lt;/NavigationContainer&gt;
);
}

getComponent загружает компонент только при первом открытии экрана, в отличие от component, который импортируется сразу.

Отличие между component и getComponent

Свойство component={...} getComponent={() => require(...)}
Время загрузки Сразу при запуске Только при первом использовании
--- --- ---
Производительность Медленнее, особенно с большим числом экранов Быстрее при старте, меньше памяти
--- --- ---
Подходит для lazy
--- --- ---

Пример плохой практики (без lazy loading)

import HomeScreen from './screens/HomeScreen';
import ProfileScreen from './screens/ProfileScreen';
&lt;Stack.Navigator&gt;
&lt;Stack.Screen name="Home" component={HomeScreen} /&gt;
&lt;Stack.Screen name="Profile" component={ProfileScreen} /&gt;
&lt;/Stack.Navigator&gt;

В этом случае оба экрана будут загружены в память при старте приложения, даже если пользователь не откроет ProfileScreen.

Пример хорошей практики (с ленивой загрузкой)

&lt;Stack.Navigator&gt;
<Stack.Screen
name="Home"
getComponent={() => require('./screens/HomeScreen').default}
/>
<Stack.Screen
name="Profile"
getComponent={() => require('./screens/ProfileScreen').default}
/>
&lt;/Stack.Navigator&gt;

Комбинирование с React.lazy() и Suspense

Если вы используете React 18, можно сделать гибридную реализацию:

const ProfileScreen = React.lazy(() => import('./screens/ProfileScreen'));
<Stack.Screen
name="Profile"
children={() => (
&lt;Suspense fallback={<Text&gt;Загрузка...&lt;/Text&gt;}>
&lt;ProfileScreen /&gt;
&lt;/Suspense&gt;
)}
/>

Однако Suspense не поддерживается во всех версиях React Native, и поведение может отличаться в зависимости от платформы (iOS, Android, Web).

Дополнительная оптимизация: код-сплитинг

Использование динамического импорта вне навигации

const loadComponent = async () => {
const module = await import('./screens/HeavyComponent');
return module.default;
};
const \[Component, setComponent\] = useState(null);
useEffect(() => {
loadComponent().then(setComponent);
}, \[\]);

Это позволяет вручную загружать компоненты по событию (например, по нажатию на кнопку).

Использование Expo с ленивой загрузкой

Expo поддерживает lazy loading аналогично обычному React Native-проекту. Главное — избегать предзагрузки всех экранов в import. Пример:

<Stack.Screen
name="Settings"
getComponent={() => require('../screens/SettingsScreen').default}
/>

Поддержка отложенной отрисовки (lazy rendering)

Помимо отложенной загрузки, можно использовать отложенную отрисовку (например, внутри табов):

&lt;Tab.Navigator screenOptions={{ lazy: true }}&gt;
&lt;Tab.Screen name="Feed" component={FeedScreen} /&gt;
&lt;Tab.Screen name="Notifications" component={NotificationsScreen} /&gt;
&lt;/Tab.Navigator&gt;

Параметр lazy: true означает, что экран не будет отрисован до тех пор, пока пользователь не перейдёт на него.

Предупреждения и ограничения

  • getComponent нельзя использовать вместе с component, только один из них

  • require() должен использовать абсолютный или относительный путь, а не переменные

  • Lazy loading не работает, если вы делаете статический импорт всех экранов в начале

  • Suspense пока не работает на 100% в React Native, особенно без React 18

Поддержка библиотеки react-native-screens

Если используется react-native-screens, то рекомендуется вызвать enableScreens() для оптимизации навигации и памяти:

import { enableScreens } from 'react-native-screens';

enableScreens();

Эта библиотека помогает уменьшить использование памяти путём размонтирования неактивных экранов и управления их жизненным циклом.

Ленивая загрузка экранов в React Native — это эффективная техника оптимизации, особенно в приложениях с множеством экранов или тяжёлыми модулями. Наиболее надёжный способ — использовать getComponent из react-navigation, который встроенно поддерживает ленивую загрузку. Это улучшает скорость старта приложения и экономит ресурсы устройства, снижая нагрузку на память и ускоряя навигацию.