React Native course ยท Module 6: Photos, camera and audio
expo-image - Optimal Image Display
In this lesson6
Welcome to the Crystal Gallery! You will learn how to handle multimedia in mobile applications.
Installing expo-image
npx expo install expo-imageBasic Usage
import { Image } from 'expo-image';
import { StyleSheet, View } from 'react-native';
function ImageGallery() {
return (
<View style={styles.container}>
{/* Image from URL */}
<Image
source={{ uri: 'https://atlantis.app/images/crystal.jpg' }}
style={styles.image}
contentFit="cover"
transition={300}
/>
{/* Local image */}
<Image
source={require('@/assets/images/pearl.png')}
style={styles.image}
contentFit="contain"
/>
{/* With placeholder and blur */}
<Image
source={{ uri: 'https://atlantis.app/images/large.jpg' }}
placeholder={blurhash}
style={styles.image}
contentFit="cover"
transition={500}
/>
</View>
);
}
const blurhash = 'L6PZfSi_.AyE_3t7t7R**0o#DgR4';
const styles = StyleSheet.create({
container: {
flex: 1,
},
image: {
width: '100%',
height: 200,
borderRadius: 12,
},
});contentFit (formerly resizeMode)
// Different fit modes
<Image source={source} contentFit="cover" /> // Fills, may crop
<Image source={source} contentFit="contain" /> // Fully visible, may have padding
<Image source={source} contentFit="fill" /> // Stretches to dimensions
<Image source={source} contentFit="none" /> // Original dimensions
<Image source={source} contentFit="scale-down" /> // contain or none (smaller)Blurhash and Placeholder
import { Image } from 'expo-image';
// Blurhash - compact placeholder
const blurhash = 'L6PZfSi_.AyE_3t7t7R**0o#DgR4';
function OptimizedImage() {
return (
<Image
source={{ uri: 'https://example.com/image.jpg' }}
placeholder={blurhash}
placeholderContentFit="cover"
style={styles.image}
transition={500}
/>
);
}Caching
import { Image } from 'expo-image';
// Cache settings
<Image
source={{ uri: imageUrl }}
cachePolicy="memory-disk" // memory, disk, memory-disk, none
style={styles.image}
/>
// Prefetching
import { Image } from 'expo-image';
async function preloadImages() {
const urls = [
'https://example.com/image1.jpg',
'https://example.com/image2.jpg',
];
await Promise.all(urls.map((url) => Image.prefetch(url)));
}Image List with FlatList
interface ImageItem {
id: string;
uri: string;
title: string;
}
function ImageList() {
const [images, setImages] = useState<ImageItem[]>([]);
return (
<FlatList
data={images}
numColumns={2}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<Pressable style={styles.imageCard}>
<Image
source={{ uri: item.uri }}
style={styles.gridImage}
contentFit="cover"
transition={200}
/>
<Text style={styles.imageTitle}>{item.title}</Text>
</Pressable>
)}
/>
);
}expo-image is significantly more performant than the standard Image from React Native!
Code for this lesson: App.tsx
import React, { useState } from 'react';
import { View, Text, FlatList, Pressable, StyleSheet } from 'react-native';
import { Image } from 'expo-image';
interface ImageItem {
id: string;
uri: string;
title: string;
}
export default function App() {
const [images] = useState<ImageItem[]>([
{ id: '1', uri: 'https://picsum.photos/200?1', title: 'Crystal' },
{ id: '2', uri: 'https://picsum.photos/200?2', title: 'Pearl' },
]);
return (
<FlatList
data={images}
numColumns={2}
keyExtractor={(item) => item.id}
contentContainerStyle={styles.grid}
renderItem={({ item }) => (
<Pressable style={styles.card}>
{/* TODO: add an <Image> from expo-image that:
- has source={{ uri: item.uri }}
- uses the styles.image style
- has contentFit="cover"
- has transition={200} for a smooth fade-in */}
<Text style={styles.title}>{item.title}</Text>
</Pressable>
)}
/>
);
}
const styles = StyleSheet.create({
grid: { padding: 8 },
card: { flex: 1, margin: 4 },
image: {
width: '100%',
height: 150,
borderRadius: 12,
},
title: {
color: '#aed6f1',
textAlign: 'center',
marginTop: 6,
},
});Docs entries used in this lesson
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. Which contentFit value fills the container, potentially cropping the image?
2. What is blurhash used for in expo-image?
Hands-on tasks in the game
- Horizontal ordering
Arrange image prefetching:
- Code editor
Complete the FlatList code with expo-image.