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.

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
contentFitsegún el tipo de contenido (por ejemplo, “contain” para logos, “cover” para fotos). - Para listas grandes, combina con
react-native-reanimatedoFlashListpara optimizar el scroll.

Ingeniero en Informática, Investigador, me encanta crear cosas o arreglarlas y darles una nueva vida. Escritor y poeta. Más de 20 APPs publicadas y un libro en Amazon.