Implementar Expo Image con React Native y Expo para acelerar la carga de imagenes y cache

Tiempo de lectura: 2 minutos

expo-image es un componente moderno de Expo optimizado para cargar imágenes de forma rápida, eficiente y con caché integrada. Está pensado para reemplazar tanto al Image nativo de React Native como a librerías externas como react-native-fast-image.

Montaña nevada - pexels

Incluye:

  • Soporte para caché de imágenes.
  • Transiciones y efectos de desenfoque.
  • Prioridad de carga.
  • Optimización en memoria y red.

2. Instalación

Si tu proyecto ya usa Expo SDK 49 o superior, puedes instalarlo directamente con:

npx expo install expo-image

Esto se encarga automáticamente de instalar la versión compatible con tu SDK.

3. Importación básica

Una vez instalado, puedes importarlo así:

import { Image } from 'expo-image';

4. Uso básico

Ejemplo simple de cómo renderizar una imagen desde una URL:

<Image
  source={{ uri: 'https://example.com/imagen.jpg' }}
  style={{ width: 200, height: 200, borderRadius: 10 }}
  contentFit="cover"
/>

5. Ejemplo completo: ExpoImageCustom

A continuación, un componente reutilizable inspirado en tu FastImageCustom, pero usando expo-image:

import React, { useState } from 'react';
import { View, ActivityIndicator, StyleSheet } from 'react-native';
import { Image } from 'expo-image';
import { marron } from '@/constants/Colors';

interface ExpoImageCustomProps {
  uri: string;
  style?: object;
  contentFit?: 'contain' | 'cover' | 'fill' | 'scale-down';
  cachePolicy?: 'none' | 'disk' | 'memory';
  onError?: () => void;
  onLoadEnd?: () => void;
  onLoadStart?: () => void;
  permitShowLoader?: boolean;
  loadingIndicatorColor?: string;
  indicatorSize?: 'small' | 'large';
}

const ExpoImageCustom: React.FC<ExpoImageCustomProps> = ({
  uri,
  style,
  contentFit = 'cover',
  cachePolicy = 'disk',
  onError,
  onLoadEnd,
  onLoadStart,
  loadingIndicatorColor = marron,
  indicatorSize = 'small',
  permitShowLoader = true,
}) => {
  const [loading, setLoading] = useState(true);

  const handleLoadStart = () => {
    setLoading(true);
    onLoadStart && onLoadStart();
  };

  const handleLoadEnd = () => {
    setLoading(false);
    onLoadEnd && onLoadEnd();
  };

  const handleError = () => {
    onError && onError();
    setLoading(false);
  };

  return (
    <View style={[styles.container, style]}>
      {permitShowLoader && loading && (
        <ActivityIndicator
          size={indicatorSize}
          color={loadingIndicatorColor}
          style={styles.loadingIndicator}
        />
      )}
      <Image
        source={{ uri }}
        style={[styles.image, style]}
        contentFit={contentFit}
        cachePolicy={cachePolicy}
        onLoadStart={handleLoadStart}
        onLoadEnd={handleLoadEnd}
        onError={handleError}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    position: 'relative',
  },
  image: {
    width: '100%',
    height: '100%',
  },
  loadingIndicator: {
    position: 'absolute',
    top: '50%',
    left: '50%',
    transform: [{ translateX: -15 }, { translateY: -15 }],
  },
});

export default ExpoImageCustom;

6. Ejemplo de uso en pantalla

import React from 'react';
import { View, StyleSheet } from 'react-native';
import ExpoImageCustom from '@/components/ExpoImageCustom';

export default function EjemploScreen() {
  return (
    <View style={styles.container}>
      <ExpoImageCustom
        uri="https://picsum.photos/400"
        style={styles.image}
        permitShowLoader={true}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  image: {
    width: 300,
    height: 200,
    borderRadius: 10,
  },
});

7. Recomendaciones de rendimiento

  • Usa cachePolicy="disk" para mantener las imágenes almacenadas entre sesiones.
  • Ajusta contentFit según el tipo de contenido (por ejemplo, “contain” para logos, “cover” para fotos).
  • Para listas grandes, combina con react-native-reanimated o FlashList para optimizar el scroll.

Deja un comentario