Image Performance with expo-image in React Native
Image Performance with expo-image
~13 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
ProductCard's <Image source={{{{ uri: imageUrl }}}}> from "React Native for Beginners" uses React Native's built-in Image component – functionally correct, but without caching control and without modern image format support. expo-image replaces it with considerably more performance features.
Installing expo-image
npx expo install expo-imageProductCard.js: replacing Image with expo-image
import { memo } from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import { Image } from 'expo-image';
const BLURHASH = '|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WVj[ayayj[fQoff7azayj[ayj[j[ayofayayayj[fQj[ayayj[ayfjj[j[ayjuayj[';
function ProductCard({ name, price, imageUrl, onPress, isFavorite, onToggleFavorite }) {
return (
<TouchableOpacity style={styles.card} onPress={onPress}>
<Image
source={imageUrl}
style={styles.image}
placeholder={{ blurhash: BLURHASH }}
contentFit="cover"
transition={200}
cachePolicy="memory-disk"
/>
<View style={styles.info}>
<Text style={styles.name}>{name}</Text>
<Text style={styles.price}>${price.toFixed(2)}</Text>
</View>
<TouchableOpacity style={styles.favoriteButton} onPress={onToggleFavorite}>
<Text style={styles.favoriteIcon}>{isFavorite ? '♥' : '♡'}</Text>
</TouchableOpacity>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
card: {
flexDirection: 'row',
padding: 12,
marginBottom: 8,
backgroundColor: '#f9fafb',
borderRadius: 8,
alignItems: 'center',
},
image: { width: 60, height: 60, borderRadius: 4 },
info: { marginLeft: 12, flex: 1 },
name: { fontSize: 16, fontWeight: '600' },
price: { fontSize: 14, color: '#6b7280' },
favoriteButton: { padding: 8 },
favoriteIcon: { fontSize: 20, color: '#ef4444' },
});
export default memo(ProductCard);The key new props in detail
source={{imageUrl}}instead ofsource={{{{ uri: imageUrl }}}}–expo-imageaccepts a plain URL string directly, theuriobject wrapping of the built-inImagecomponent is no longer needed.placeholder={{{{ blurhash: BLURHASH }}}}– shows a blurred placeholder (generated from a compact text string, seeblurha.shfor creating your own values) WHILE the real image loads, instead of an empty gray rectangle.contentFit="cover"– the direct equivalent of CSS'object-fit, or the built-inImagecomponent'sresizeModeprop (see "React Native Reference", the "Background Image" topic), just with clearer naming.transition={{200}}– a smooth fade-in (200ms) instead of an abrupt appearance once the image finishes loading.cachePolicy="memory-disk"– THE decisive performance difference from the built-inImagecomponent, see the next section.
cachePolicy in detail: why it matters
React Native's built-in Image component only caches images UNRELIABLY/platform-dependently – a product you visit multiple times (product list → detail → back → detail again) often reloads its image MULTIPLE times over the network. cachePolicy="memory-disk" enables TWO cache layers:
- Memory cache: already-decoded images stay in RAM – INSTANT display when re-rendering the same image URL within the same app session.
- Disk cache: downloaded image data stays saved on the device – no repeat network download needed, even after an app restart, as long as the cache hasn't been cleared.
Bonus: prefetching images with Image.prefetch
For an even smoother experience, images can be preloaded BEFORE they become visible – e.g. right after the product list finishes loading in ProductListScreen:
import { Image } from 'expo-image';
// After the successful fetchProducts() call:
Image.prefetch(items.map((product) => product.imageUrl));When the user then actually scrolls, the images are often already in the disk cache – FlatList no longer has to wait for the network download, only for the (very fast) cache read.
Tipp: Rule of thumb for image performance: expo-image with cachePolicy="memory-disk" is practically ALWAYS the right choice over the built-in Image component, as soon as an app shows more than one or two images – the switch costs little effort (usually just an import swap plus renaming a few props), the performance gain for repeatedly displayed images (like our product images) is substantial.