Как реализовать кэширование изображений?

В React Native кэширование изображений — это важная практика для оптимизации производительности, ускорения загрузки и уменьшения количества сетевых запросов. Особенно это актуально при отображении изображений из сети (например, с CDN или API), когда одни и те же изображения повторяются в списках или на разных экранах.

Базовый Image компонент из react-native не поддерживает кэширование на Android, а на iOS — только частично, что делает его непригодным для серьёзного использования в продуктивных проектах.

Стандартный Image и его ограничения

import { Image } from 'react-native';

<Image
source={{ uri: 'https://example.com/image.jpg' }}
style={{ width: 100, height: 100 }}
/>

Проблемы:

  • На Android изображения всегда загружаются заново

  • На iOS они кэшируются системой, но не управляемо

  • Нет контроля над стратегиями кэширования, размером, приоритетом загрузки

  • Нет прогресс-индикатора

Лучшее решение — react-native-fast-image

react-native-fast-image — это высокопроизводительный компонент-замена для Image, основанный на нативных библиотеках:

  • iOS: SDWebImage

  • Android: Glide

Библиотека поддерживает:

  • Кэширование (memory + disk)

  • Приоритеты загрузки

  • Прогресс и обработку ошибок

  • Использование HTTP-заголовков

  • Resize modes, как в стандартном Image

Установка react-native-fast-image

npm install react-native-fast-image

Для bare React Native (не Expo) может потребоваться npx pod-install для iOS и gradlew clean на Android.

Expo не поддерживает FastImage из коробки. Использование возможно через Expo Dev Client с prebuild.

Пример использования

import FastImage from 'react-native-fast-image';
<FastImage
style={{ width: 100, height: 100 }}
source={{
uri: 'https://example.com/image.jpg',
priority: FastImage.priority.normal,
cache: FastImage.cacheControl.immutable, // или web, cacheOnly
}}
resizeMode={FastImage.resizeMode.cover}
/>

Настройки cacheControl

FastImage.cacheControl управляет стратегией кэширования:

  • immutable — кэширует изображение навсегда (лучший вариант для CDN)

  • web — соблюдает HTTP cache headers (как браузер)

  • cacheOnly — загружает только из кэша, не делает сетевой запрос

Обработка ошибок и индикаторы

<FastImage
style={{ width: 200, height: 200 }}
source={{ uri: 'https://example.com/image.jpg' }}
onLoadStart={() => console.log('Загрузка началась')}
onProgress={e => console.log('Прогресс', e.nativeEvent.loaded / e.nativeEvent.total)}
onLoad={() => console.log('Загрузка завершена')}
onError={() => console.log('Ошибка загрузки')}
/>

Работа с FlatList и FastImage

FastImage особенно полезен при отображении списка изображений, т.к. предотвращает повторную загрузку и визуальные глитчи:

<FlatList
data={images}
renderItem={({ item }) => (
<FastImage
style={{ width: 100, height: 100 }}
source={{ uri: item.url, priority: FastImage.priority.high }}
/>
)}
keyExtractor={item => item.id}
/>

Продвинутые стратегии кэширования

  1. **Предзагрузка изображений:
    **
FastImage.preload(\[
{ uri: 'https://example.com/image1.jpg' },
{ uri: 'https://example.com/image2.jpg' },
\]);

Это загружает изображения в кэш до их использования, полезно для splash-экранов или прелоадинга ассетов.

  1. **Очистка кэша вручную:
    **
FastImage.clearMemoryCache();
FastImage.clearDiskCache();

Полезно при логине нового пользователя или очистке временных данных.

  1. **Использование HTTP-заголовков:
    **
source={{
uri: 'https://example.com/secure-image.jpg',
headers: {
Authorization: 'Bearer token',
},
cache: FastImage.cacheControl.web,
}}

Это даёт возможность работать с изображениями, требующими авторизации.

Альтернативы для Expo

Так как react-native-fast-image не работает в Expo Go, доступны другие варианты:

  1. expo-image (с SDK 48+) — экспериментальный компонент от Expo:
import { Image } from 'expo-image';
<Image
source="https://example.com/image.jpg"
contentFit="cover"
style={{ width: 100, height: 100 }}
/>

Поддерживает:

  • Кэширование на диске

  • Async load

  • Progressive rendering

  • **Кэширование вручную через FileSystem:
    **

import \* as FileSystem from 'expo-file-system';
const localUri = \`${FileSystem.cacheDirectory}image.jpg\`;
const download = await FileSystem.downloadAsync(
'https://example.com/image.jpg',
localUri
);

После загрузки можно использовать Image с uri: download.uri.

Общие советы

  • Всегда указывай фиксированные размеры изображений (width и height) для предотвращения лишних перерасчётов layout

  • Используй resizeMode='cover' или contain в зависимости от макета

  • Старайся использовать CDN с правильными заголовками cache-control для web стратегии

  • Предзагружай изображения на экранах, где они появятся позже

  • Храни аватары и часто используемые изображения на устройстве или в кэше, чтобы сократить повторные запросы

Кэширование изображений в React Native — ключевой шаг к созданию отзывчивых, плавных и экономных по трафику мобильных приложений. Использование FastImage или expo-image позволяет добиться профессионального UX без лишней нагрузки на сеть и память устройства.