Какие есть способы оптимизации производительности?
Оптимизация производительности в React Native играет критически важную роль при создании мобильных приложений, особенно когда речь идёт о сложных интерфейсах, больших объёмах данных и анимациях. Поскольку React Native работает в двух разных средах — JavaScript и нативной — необходимо учитывать оба уровня, чтобы обеспечить плавную, быструю и отзывчивую работу приложения. Существует множество способов улучшить производительность, начиная с оптимизации рендера компонентов и заканчивая контролем над работой bridge и использованием инструментов платформы.
1. Оптимизация рендеринга компонентов
Использование React.memo
Позволяет избежать повторного рендера функциональных компонентов, если их props не изменились.
const MyComponent = React.memo(({ title }) => {
return <Text>{title}</Text>;
});
shouldComponentUpdate и PureComponent
Для классовых компонентов можно переопределить shouldComponentUpdate, чтобы контролировать обновления.
class MyComponent extends React.PureComponent {
render() {
return <Text>{this.props.name}</Text>;
}
}
PureComponent делает поверхностное сравнение props и state и автоматически предотвращает лишние рендеры.
2. Мемоизация значений и функций
useMemo
Кэширует вычисления, чтобы они не выполнялись заново при каждом рендере.
const result = useMemo(() => expensiveCalculation(data), [data]);
useCallback
Кэширует функции, чтобы не создавать новую ссылку при каждом рендере.
const handlePress = useCallback(() => {
// ...
}, \[dependency\]);
3. Использование списков эффективно
FlatList вместо ScrollView для длинных списков
ScrollView отрисовывает все дочерние компоненты сразу, тогда как FlatList использует виртуализацию — отображает только видимые элементы, загружая остальные по мере прокрутки.
<FlatList
data={myData}
renderItem={({ item }) => <Text>{item.name}</Text>}
keyExtractor={item => item.id}
/>
Настройка initialNumToRender, windowSize, maxToRenderPerBatch
Позволяет точно управлять количеством элементов, загружаемых в память:
<FlatList
initialNumToRender={10}
windowSize={5}
maxToRenderPerBatch={8}
/>
4. Оптимизация изображений
-
Используйте изображения в нужном разрешении (избегайте оригиналов 4K для иконок)
-
Предзагружайте изображения с Image.prefetch(url)
-
Используйте resizeMode и cache:
<Image
source={{ uri: '...', cache: 'force-cache' }}
resizeMode="contain"
/>
- Используйте библиотеки для оптимизации загрузки, например, react-native-fast-image
5. Lazy loading экранов и компонентов
Для больших экранов или модулей применяйте отложенную загрузку:
<Stack.Screen
name="Settings"
getComponent={() => require('./screens/Settings').default}
/>
Или:
const LazyComponent = React.lazy(() => import('./MyHeavyComponent'));
6. Избегание ненужных ререндеров
-
Следите за тем, чтобы компоненты не перерисовывались при каждом изменении родителя.
-
Не передавайте анонимные функции и новые объекты/массивы в props без необходимости:
// Плохо:
<MyComponent data={\[\]} onPress={() => {}} />
// Лучше:
const data = useMemo(() => \[...\], \[\]);
const onPress = useCallback(() => {...}, \[\]);
7. Использование InteractionManager
Позволяет отложить выполнение тяжёлых операций до завершения всех анимаций и взаимодействий:
import { InteractionManager } from 'react-native';
useEffect(() => {
const task = InteractionManager.runAfterInteractions(() => {
// тяжёлые вычисления
});
return () => task.cancel();
}, \[\]);
8. Выгрузка неиспользуемых экранов и компонентов
В React Navigation можно размонтировать экран при уходе с него:
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={{ unmountOnBlur: true }}
/>
Это освобождает память и снижает нагрузку.
9. Управление памятью
-
Очищайте подписки, таймеры и слушатели в useEffect
-
Не забывайте clearInterval, clearTimeout, removeListener
-
Используйте WeakRef или WeakMap, если необходимо
10. Анимации с использованием Reanimated или NativeDriver
React Native по умолчанию использует JavaScript-драйвер для анимаций, который может быть лагучим.
Рекомендуется использовать native driver:
Animated.timing(this.state.value, {
toValue: 1,
useNativeDriver: true
}).start();
Либо использовать более производительную библиотеку:
11. Использование useFocusEffect вместо useEffect
Если компонент должен выполнять действия при фокусе экрана, лучше использовать useFocusEffect из @react-navigation/native:
import { useFocusEffect } from '@react-navigation/native';
useFocusEffect(
useCallback(() => {
// Выполнить при заходе на экран
return () => {
// Очистка при выходе с экрана
};
}, \[\])
);
Это предотвращает ненужные эффекты, когда экран не в фокусе.
12. Включение Hermes
Hermes — это JavaScript-движок, разработанный Facebook специально для React Native. Он:
-
Ускоряет запуск приложения
-
Уменьшает потребление памяти
-
Поддерживает JSI (новая архитектура)
Чтобы включить Hermes:
Для Android:
В android/app/build.gradle:
project.ext.react = \[
enableHermes: true
\]
13. Профилирование и отладка
Используйте инструменты анализа производительности:
-
Flipper с плагинами React DevTools и Performance Monitor
-
Встроенные DevMenu и React Native Inspector
-
Android Studio и Xcode Instruments
-
why-did-you-render — отслеживает лишние ререндеры
npm install @welldone-software/why-did-you-render
if (\__DEV_\_) {
const whyDidYouRender = require('@welldone-software/why-did-you-render');
whyDidYouRender(React);
}
14. Разбиение больших компонентов
-
Разделяйте крупные экраны на мелкие переиспользуемые компоненты
-
Не загромождайте один компонент множеством логик и состояний
-
Выносите тяжёлые элементы (например, сложные списки, изображения) в отложенные компоненты
15. Использование дебаунса и троттлинга
Для предотвращения перегрузки UI/сети при частых событиях (например, скролле, вводе текста):
import debounce from 'lodash.debounce';
const handleSearch = debounce((text) => {
// отправка запроса
}, 300);
Оптимизация React Native-приложения требует комплексного подхода: от снижения количества перерисовок компонентов до контроля загрузки данных и использования нативных инструментов. Регулярное профилирование и анализ производительности позволяют находить узкие места и устранять их до того, как они начнут влиять на пользовательский опыт.