List nhiều ảnh thường gặp:
1. Layout shift do ảnh chưa load: ảnh remote không có intrinsic size → khi load xong, item thay đổi chiều cao → list jump. Fix: set width/height cứng hoặc aspectRatio.
2. White flash trước khi ảnh load: dùng placeholder. Với expo-image:
<Image
source={{ uri }}
placeholder={{ blurhash: 'L6PZfSi_.AyE_3t7t7R**0o#DgR4' }}
transition={200}
/>Blurhash là string ngắn (28 chars) encode preview blur — encode lúc upload server, decode trong app gần như miễn phí.
3. Prefetch ảnh sắp scroll tới:
import { Image } from 'expo-image'
await Image.prefetch([url1, url2, url3]) // download trước, vào disk cacheGọi trong onEndReached của FlatList khi user scroll gần cuối — pre-fetch trang sau.
4. Thumbnail/full-res hai-bước: load ảnh nhỏ trước, swap sang full-res khi sẵn sàng. expo-image có recyclingKey + priority hỗ trợ pattern này.
5. Memory blow-up: ảnh 4K hiển thị 100×100 vẫn decode full size vào RAM. Fix: server return URL có ?w=200&h=200 hoặc dùng image CDN (Cloudinary, imgix). Trên client, resizeMode="cover" không downsample — phải dùng expo-image với transition={...} và prop contentFit (chỉ format hiển thị).
6. Cache invalidation: key uri cần stable. Nếu URL đổi mỗi request (signed URL có timestamp), cache không hit. Dùng cachePolicy="memory-disk" + tách signing parameter.
Heavy-image lists commonly hit:
1. Layout shift from late-loading images: remote images have no intrinsic size, so the row's height changes when they finally load → list jumps. Fix: set explicit width/height or aspectRatio.
2. White flash before load: use a placeholder. With expo-image:
<Image
source={{ uri }}
placeholder={{ blurhash: 'L6PZfSi_.AyE_3t7t7R**0o#DgR4' }}
transition={200}
/>A blurhash is a short string (28 chars) encoding a blurred preview — generate server-side at upload, decode nearly for free in the app.
3. Prefetch upcoming images:
import { Image } from 'expo-image'
await Image.prefetch([url1, url2, url3]) // warms the disk cacheCall it from onEndReached when the user is near the end — pre-fetch the next page.
4. Two-step thumbnail/full-res: show a small image first and swap to the full one when ready. expo-image's recyclingKey + priority support this pattern.
5. Memory blow-up: a 4K image rendered at 100×100 still decodes at full size into RAM. Fix: have the server return ?w=200&h=200 URLs or use an image CDN (Cloudinary, imgix). On the client, resizeMode="cover" does not downsample — use expo-image's contentFit only for layout fit.
6. Cache invalidation: the uri key must be stable. If the URL changes per request (signed URLs with timestamps), the cache misses. Use cachePolicy="memory-disk" and separate the signing query out.