skip to content

In a React Native listing gallery, how would you use Image.prefetch, Image.queryCache and Image.getSize so the next photo appears instantly at the right shape?

level: seniorimportance: should knowfreq 30%

answer

  1. warm the cache one step ahead
  2. prefetch resolves a boolean
  3. queryCache: memory, disk or absent
  4. getSize may download the image
  5. prefetch takes a URL, no headers

basics

~20 s

Prefetch the next one or two photos with Image.prefetch(url) so they are in the disk cache before the swipe, check what is already cached with Image.queryCache(urls), and use Image.getSize only when the API gives no aspect ratio, since it may download the image.

solid answer

~50 s

`Image.prefetch(url)` downloads a remote image to the disk cache and resolves to a boolean; on Android it can also report a request id that `Image.abortPrefetch` cancels. In a gallery, prefetch the next one or two photos as the user lands on each one, not the whole listing, to spare bandwidth. `Image.queryCache(urls)` resolves to a map from URL to `'memory'`, `'disk'` or `'disk/memory'`, and a URL missing from the map is not cached, which helps decide whether to show a thumbnail first. `Image.getSize(url)` resolves to pixel `width` and `height` so you can set an `aspectRatio`, but it may download the image, so prefer ratios from the listing API. Note that `prefetch` takes only a URL, while `getSizeWithHeaders` exists for authenticated images. On iOS, a source's `cache: 'only-if-cached'` shows an image only when it is already cached.

code

tsx · 18 lines
tsx
import {useEffect} from 'react';
import {Image} from 'react-native';

export function usePrefetchAhead(urls: string[], index: number, ahead = 2) {
  useEffect(() => {
    const next = urls.slice(index + 1, index + 1 + ahead);
    if (next.length === 0) return;

    Image.queryCache(next)
      .then(cached => {
        const missing = next.filter(url => !(url in cached));
        return Promise.all(missing.map(url => Image.prefetch(url).catch(() => false)));
      })
      .catch(() => {
        // A failed prefetch only means the Image downloads on demand.
      });
  }, [urls, index, ahead]);
}

go deeper

for a junior

Recall that Image.prefetch warms the cache for a URL and that remote images need their size known before rendering.

for a middle

Explain what prefetch, queryCache and getSize return, the Android-only request id and abortPrefetch, and the iOS-only cache source option.

for a senior

Design a prefetch window for a gallery that balances instant swipes against wasted bandwidth, and get aspect ratios from the API rather than getSize.

for a principal

Negotiate image metadata and variant sizes in the content API so every client can render galleries quickly without runtime measurement.

## The goal In a full-screen listing gallery, users swipe through twenty photos of a property. Two things make it feel slow: the next photo appearing only after a visible download, and the photo's frame jumping when its real shape becomes known. React Native's `Image` statics address both, within limits. ## Image.prefetch `Image.prefetch(url)` downloads a remote image **to the disk cache** for later use and returns a **promise that resolves to a boolean**. When the user swipes and an `Image` with that `uri` mounts, it can be served from the cache instead of the network. - On **Android**, `prefetch` also accepts a callback that receives a **request id**, and `Image.abortPrefetch(requestId)` cancels the request, for example when the user leaves the gallery. - `prefetch` takes **only a URL**. Images that need request headers, such as authorisation, cannot be prefetched with their headers this way. A sensible policy in a gallery: 1. When photo *n* becomes visible, prefetch *n + 1* and *n + 2*. 2. Do not prefetch the whole listing: twenty full-size photos cost bandwidth and storage for images the user may never see. 3. Cancel outstanding prefetches on Android when the screen closes. 4. Treat a `false` or rejected result as "not cached"; the `Image` will simply download on demand. ## Image.queryCache `Image.queryCache(urls)` resolves to an object mapping each **cached** URL to `'memory'`, `'disk'` or `'disk/memory'`. A URL that is **absent** from the result is not cached. Uses: - decide whether to show a low-resolution thumbnail first or go straight to the full photo; - measure how well the prefetch policy is working during development; - avoid re-prefetching images that are already on disk. ## Image.getSize and the shape problem `Image.getSize(url)` resolves to `{width, height}` **in pixels**, which lets you set `aspectRatio: width / height` before rendering. There is also a callback form. Its costs: - to learn the size, the image **may first be downloaded** (and is then cached); - the docs say that although this could be used to preload, it is **not optimised for that** and may change; - `getSizeWithHeaders(url, headers)` exists for images that need request headers. So `getSize` is a fallback. The dependable answer is to include **width and height or an aspect ratio in the listing API**, so every photo's frame is right before any download. | Need | Tool | Cost | |---|---|---| | Next photo instant | `Image.prefetch` | bandwidth for photos the user might skip | | Know what is cached | `Image.queryCache` | a native call, no download | | Photo shape before render | ratio from the API | none at runtime | | Photo shape, no API data | `Image.getSize` | may download the image | ## iOS cache policy on the source On iOS the `source` object accepts `cache`: `'default'`, `'reload'`, `'force-cache'` or `'only-if-cached'`. `'only-if-cached'` shows an image only if it is already cached and otherwise treats the load as failed, which suits a low-resolution placeholder that should never trigger its own download. This option is iOS-only; Android has no equivalent on the `source` object. ## Where this stops These APIs cover warming and inspecting the platform image cache. How big that cache is, how many resolution variants a server should produce, and how decoded bitmaps affect memory are separate concerns. For a gallery, the core toolset is: ratios from the API, prefetch one or two ahead, and let `Image` read from the cache. ## Checking that it works Measure before and after: log `Image.queryCache` for the next few URLs when a photo becomes visible, and count how often the next photo is already on `'disk'` or in `'memory'` by the time the user swipes. If most are cached, the window is large enough; if users on slow connections still wait, prefetch earlier rather than further ahead.

  • In React Native, why is Image.getSize a poor way to learn the shape of every photo in a gallery?
    To report a size, `Image.getSize` may have to download the image first, so calling it for every photo adds network work before layout and still leaves frames unknown until each call resolves. The docs also say it is not optimised for preloading. Aspect ratios delivered by the listing API make every frame correct immediately, with no runtime cost.
  • In React Native, how do you cancel a prefetch when the user leaves the gallery?
    On Android, `Image.prefetch` accepts a callback that receives a request id, and `Image.abortPrefetch(requestId)` cancels that request. `abortPrefetch` is Android-only; on iOS there is no public cancel for `prefetch`, so the practical control is to prefetch only a small window ahead.
  • In React Native, what does Image.queryCache return for a URL that has never been loaded?
    Nothing for that URL: `queryCache` resolves to an object that only contains URLs that are cached, each mapped to `'memory'`, `'disk'` or `'disk/memory'`. A URL missing from the object is not in the cache.

saying these in an interview costs you the question

  • Image.prefetch loads the image into memory and returns its dimensions.
  • Prefetching every photo in the listing up front is the fastest strategy.
  • Image.getSize reads the size without downloading anything.
  • Image.abortPrefetch works on both iOS and Android.
  • The source cache option controls caching on Android too.