DylanVann/react-native-fast-image(新しいタブで開きます)
主要言語: TypeScript
Performant React Native image component.
- star 数
- 8,420
- watcher 数
- 52
- fork 数
- 1,520
- issue 数
- 13
- 最終更新
- 2026/10/31
主要言語: TypeScript
Performant React Native image component.
Performant React Native image component.
React Native's Image component handles image caching like browsers for the most part. If the server is returning proper cache control headers for images you'll generally get the sort of built in caching behavior you'd have in a browser. Even so, many people have noticed:
FastImage is an Image replacement that solves these issues. FastImage is a wrapper around SDWebImage (iOS) and Glide (Android).
headers).priority).source).transition).placeholder).FastImageBackground for content over an image.| Format | iOS | Android |
|---|---|---|
| JPEG | ||
| PNG | ||
| APNG | ||
| GIF | ||
| WebP | ||
| AVIF | ||
| HEIC | ||
| SVG | ||
| ICO | ||
| BMP | ||
| TIFF | ||
| ICNS | ||
| PSD |
See Formats for the versions of iOS and Android each format needs, and what decodes it.
npm install react-native-fast-image cd ios && pod install
With Expo:
npx expo install react-native-fast-image
It has native code, so it needs a development build (e.g. npx expo run:ios), not Expo Go.
Needs React Native 0.83 or later with the New Architecture (Expo SDK 55 or later) and React 19, iOS/tvOS 15.1 or later, and Android 7.0 (API 24) or later; on tvOS, it works with React Native tvOS. Apps on the legacy architecture or older React Native can use FastImage 9 (npm install react-native-fast-image@9). Upgrading from FastImage 9: see Upgrading from 9.x.
To set the cache's size when the app starts, see Native config.
If your Android app has its own Glide AppGlideModule, read using FastImage with an AppGlideModule first, or FastImage may not work.
If pod install can't find a compatible SDWebImage (FastImage needs 5.21.5 or later), update it with cd ios && pod update SDWebImage.
import FastImage from 'react-native-fast-image' const YourImage = () => ( <FastImage style={{ width: 200, height: 200 }} source={{ uri: 'https://example.com/image.jpg', headers: { Authorization: 'someAuthToken' }, priority: 'normal', }} objectFit="contain" /> )
It's a single native view, which also takes React Native's View props, such as accessibility props, focus (focusable and tabIndex, and onFocus and onBlur on Android and Apple TV), testID, nativeID, onLayout, pointerEvents and hitSlop. A ref to it is that view (e.g. for measure), with reload(). It doesn't take children: use FastImageBackground for content over an image.
Platforms: Android, iOS, tvOS, Web · Type: number | Source | (number | Source)[]
Source for the remote image to load: a Source, a require()d image, or an array of the same image at different sizes.
When source changes, the image that's showing stays until the new one has loaded. In views that get reused for other content, such as rows in FlashList or recyclerlistview, set recyclingKey so a reused row doesn't show the previous row's image.
Several sizes of an image. source can also be an array of the same image at different sizes, each with its width and height in pixels (times scale, if it has one). The view loads the one whose size is closest to its own, in pixels, so a small view downloads a small image:
<FastImage style={{ width: 120, height: 120 }} source={[ { uri: 'https://example.com/photo-200.jpg', width: 200, height: 200 }, { uri: 'https://example.com/photo-800.jpg', width: 800, height: 800 }, ]} />
onLoad) loads the largest.transition.cacheKey applies to its own entry: give each size its own key (or none), or the sizes would replace each other in the cache.FastImage.preload, getCachePath and writeToCache take one size: pass the one a view will show. An array fails with { ok: false, error }.require()d image can be one of the sizes: its size is the file's.Platforms: Android, iOS, tvOS, Web · Type: string
Remote url to load the image from. e.g. 'https://example.com/image.jpg'.
Also loads local files (file://, and on Android content://), images in the app by name (e.g. 'my_image': in its asset catalog on iOS, a drawable on Android), photo library images on iOS and tvOS (ph://, see Photo library images) and SVG images (see SVG images).
Platforms: Android, iOS, tvOS · Type: { [key: string]: string }
Headers to load the image with. e.g. { Authorization: 'someAuthToken' }.
Platforms: Android, iOS, tvOS, Web · Type: Priority · Default: 'normal'
A hint for which images to start loading first when several are waiting: 'high' ones before 'normal' ones, and 'low' ones after. It's best effort, not an order: several images load at once, and when each finishes depends on its size and the network.
'low': e.g. images further down a list.'normal': the default.'high': e.g. the image the screen is about.On the web, it's the image's fetchpriority.
Platforms: Android, iOS, tvOS · Type: Cache · Default: 'immutable'
How fresh the image must be. See how caching is handled for how the options fit together.
'immutable': loads the image once, then shows the cached copy until its url (or cacheKey) changes.'web': follows the server's HTTP cache headers, as a browser does, checking with the server when it loads. These responses are kept in their own HTTP cache (50 MB on each platform), which clearDiskCache also clears.'cacheOnly': only shows a cached image, without making a request.A data uri ignores it: its image is never downloaded.
Platforms: Android, iOS, tvOS · Type: string
The key the image is cached under, instead of its uri. Use it for urls that change while the image stays the same, e.g. signed urls with a token or an expiry. Use something that identifies the image, and change it when the image changes (e.g. include a version or the time it was updated), or the old image keeps showing.
Not used with cache: 'web', which follows the HTTP cache (keyed by url).
<FastImage source={{ uri: signedUrl, cacheKey: `avatar-${user.id}-${user.avatarUpdatedAt}`, }} />
Platforms: Android, iOS, tvOS · Type: boolean · Default: true
Whether the decoded image is kept in the memory cache. With false it's only kept on disk: a view doesn't leave it in memory once it stops showing it, and FastImage.preload downloads it without decoding it. Use it for large images that are shown once or rarely, like a full-screen photo: a decoded photo can take tens of MB of memory. Images shown again, like a list scrolled back, are decoded from disk again.
Platforms: Android, iOS, tvOS · Type: boolean · Default: true
Whether the image is kept on disk. With false it isn't kept in the disk cache or an HTTP cache, or read from them. Use it for images the app shouldn't keep once they've been shown (e.g. disappearing messages, or where a security policy doesn't allow caching sensitive images), images that change every time they load, or large images shown once, which would push other images out of the disk cache. The image is downloaded again whenever it isn't in memory, e.g. for a view of another size (or on Android, a change of blurRadius or objectFit), so with memoryCache: false too it's downloaded each time it's shown. With cache: 'web' it isn't kept in memory either, so it's downloaded every time it loads. With cache: 'cacheOnly' it's only looked for in memory. On Android, a large download is held in a temporary file while it loads, as every download is, deleted as soon as it's opened.
FastImage.preload, getCachePath and writeToCache resolve not ok for it: there's no file, and a view decodes the image for its own size, so it may download a preloaded one again. A source for the same url (or cacheKey) without diskCache: false still stores the image.
A data uri's image is kept on disk too, unless it's false.
Platforms: Android, iOS, tvOS, Web · Type: string
A ThumbHash of the image, shown blurred while the image loads, and if it fails to load. It's a short string you make when the image is uploaded (e.g. with the thumbhash package) and send with the image's url.
On the web, it needs import 'react-native-fast-image/thumbhash' (see ThumbHashes on the web).
<FastImage source={{ uri: photo.url, thumbhash: photo.thumbhash }} />
Platforms: Android, iOS, tvOS, Web · Type: string
A tiny version of the image (e.g. 8 to 20 px) as a data uri, shown blurred while the image loads, and if it fails to load. On the web it shows without any JavaScript, e.g. in a server-rendered page.
<FastImage source={{ uri: photo.url, blurDataUri: photo.lqip }} />
Platforms: Android, iOS, tvOS, Web · Type: number
With several sources (source as an array), the image's width at this uri, in pixels (times scale, if given).
Platforms: Android, iOS, tvOS, Web · Type: number
With several sources (source as an array), the image's height at this uri, in pixels (times scale, if given).
Platforms: Android, iOS, tvOS, Web · Type: number
With several sources, the scale width and height are multiplied by.
Platforms: Android, iOS, tvOS, Web · Type: string | number | SourcePlaceholder | PlaceholderSource
A placeholder shown while the image loads, and if it fails to load:
require(): placeholder={require('./gray.png')}.placeholder="data:image/png;base64,…".placeholder="gray".placeholder={{ thumbhash }}.placeholder={{ blurDataUri }}.placeholder="https://example.com/placeholder.png", or a source with headers or a cacheKey: placeholder={{ uri, headers }}.placeholder={{ uri, cache: 'cacheOnly' }}.A source's own thumbhash or blurDataUri is shown instead, if it has one; a url placeholder shows over it once it has loaded.
Notes:
require()d image doesn't show in debug builds, where the dev server serves it. Release builds show it.'cacheOnly': a browser can't look only in its cache.Platforms: Android, iOS, tvOS, Web · Type: number
Deprecated: Use placeholder, which does the same. With both, placeholder shows.
Platforms: Android, iOS, tvOS, Web · Type: ObjectFit · Default: 'cover'
How the image fits the view, as CSS's object-fit does.
'cover': scales it uniformly (keeping its aspect ratio) so it covers the view (inside its borders), cropping what doesn't fit.'contain': scales it uniformly (keeping its aspect ratio) so all of it fits in the view (inside its borders).'fill': scales its width and height separately to fill the view, which can change its aspect ratio.'none': shows it at its own size, centered, cropped if it's larger than the view.'scale-down': shows it at its own size, centered, or scaled down uniformly to fit if it's larger than the view (the smaller of 'none' and 'contain').An image's own size is its size in pixels, as points (dp on Android), as CSS counts an image's pixels: a 300 × 200 image is 300 × 200 points. A bundled image (require()) is its size in points.
It can also be set in style; the prop wins.
Platforms: Android, iOS, tvOS, Web · Type: ObjectPosition · Default: '50% 50%'
Where the image is in the view, as CSS's object-position places it: where its edges are when it doesn't fill the view exactly (contain, cover, none and scale-down; with fill it always fills it).
'top', 'left bottom'), lengths in points ('10px 20px', with px) or percentages ('25% 75%'), or offsets from an edge ('right 10px bottom 20%'). A percentage puts that point of the image at that point of the view: '0% 0%' is the top-left corner, '100% 100%' the bottom-right.top and bottom and one of left and right, each in points (a number) or a percentage ('25%'), e.g. { right: 10, bottom: '20%' }. A missing axis is centered.Points are dp on Android. An invalid value is ignored (the image is centered), with a warning in development. Placeholders are placed the same way.
<FastImage source={{ uri }} objectFit="cover" objectPosition="top" />
Platforms: Android, iOS, tvOS · Type: string | null
For views that get reused for other content, such as rows in FlashList or recyclerlistview. Set it to something that identifies the content, e.g. the item's id. When it changes, the image is cleared right away (to placeholder, or blank) instead of staying until the new one has loaded. Unlike changing key, this keeps the view, which is what list recycling is for.
<FastImage recyclingKey={item.id} source={{ uri: item.imageUrl }} />
Platforms: Android, iOS, tvOS · Type: number | boolean
How many times an animated image (GIF, animated WebP, APNG, or animated AVIF) plays:
true: forever.false: once.Changing it restarts the animation.
Platforms: Android, iOS, tvOS · Type: 'auto' | 'smooth' | 'pixelated' · Default: 'auto'
How the image is filtered when it's drawn smaller or larger than its size (like CSS's image-rendering):
'auto': the platform's usual filtering.'smooth': iOS only. Keeps a large image drawn much smaller than its size (e.g. a big photo as a thumbnail, or fine lines and text) from looking jagged or noisy. Such an image is already decoded at about the view's size by default (see downsample), so this is for images shown at less than half their size with downsample={false}, or a little smaller than their size. It uses more memory: the image is also kept at smaller sizes for drawing, about a third more than the decoded image. On Android it's the same as 'auto'.'pixelated': sharp pixels, without smoothing, e.g. for pixel art drawn larger than its size. On Android, animated images are still smoothed.Platforms: Web · Type: 'lazy' | 'eager' · Default: 'lazy'
Whether the image loads as it nears the screen ('lazy') or at once ('eager').
Platforms: Web · Type: string · Default: 'auto, 100vw'
With several sources, the width the image is shown at, as the image's sizes, so the browser loads the size that fits. The default is the width the image is laid out at, which needs loading="lazy" (otherwise, or in browsers without it, the window's width).
Platforms: Android, iOS, tvOS · Type: boolean
Pauses an animated image (GIF, animated WebP, APNG, or animated AVIF) on the frame it's showing; false plays it again from there (on Android, an animated WebP or AVIF plays again from its first frame: Android can't resume one). Each image animates on its own, so pausing one doesn't pause others showing the same file.
Platforms: Android, iOS, tvOS · Type: number | boolean | Transition | null
Fades the image in when it loads. true fades for the default's duration (see FastImage.setDefaults), or the platform's usual length if the default doesn't fade; a number is the duration in milliseconds, false (or 0) is no fade, or pass a Transition.
By default, images fade in on Android (300 ms), and not on iOS. FastImage.setDefaults changes that for every image; an image's own transition wins, and the settings it leaves out come from the default. null is the default.
Downloads, local files (file://, content://) and bundled images (require()) fade in. In lists that reuse views (e.g. FlashList), set recyclingKey, so a reused view starts empty and its image fades in, instead of showing the previous item's image until it loads.
<FastImage source={{ uri }} transition /> <FastImage source={{ uri }} transition={500} /> <FastImage source={{ uri }} transition={{ betweenImages: true, skipOnCacheHit: 'none' }} />
Platforms: Android, iOS, tvOS · Type: boolean · Default: true
Decodes a large image at about the size it's shown at, instead of at full size, so it takes much less memory.
true: an image at least twice the size its view needs is decoded at about the view's size (on Android, any image larger than its view), and an SVG is drawn at the size it's shown at. If the view grows, the image is decoded again for its new size (from the disk cache).false: images are decoded at full size, e.g. for an image that's zoomed in on with a transform (a pinch-to-zoom viewer), which would otherwise show the smaller copy enlarged. It uses more memory: a 12-megapixel photo takes about 48 MB decoded, however small it's shown. On Android, an image over 16 megapixels (4096 × 4096, 64 MB) is decoded at the largest size under that, which Android can still draw. On iOS, an image over 64 megapixels (8192 × 8192) is decoded at 16 megapixels, except with objectFit="none", which shows it at its own size. On iOS, an SVG is drawn at its own size, or the view's if that's larger.It doesn't change onLoad's width and height (the image's own size) or the cached file. Photo library images are always decoded at about the view's size. Android 16 and later decode animated WebP at full size either way, and scale it as they draw it.
If you control the images, serve them at the size they're shown (resized on your server or by an image CDN), which also saves bandwidth.
Platforms: iOS 17+, tvOS 17+, Web · Type: 'standard' | 'constrained' | 'no-limit'
How bright HDR photos (e.g. photos taken on an iPhone) can be, on displays that support it:
'standard': in standard range, like the rest of the screen.'constrained': in HDR, their highlights brighter than the rest of the screen but held below the display's peak, e.g. for images among other content (a feed).'no-limit': in full HDR, e.g. for a full-screen photo viewer.Not set, iOS shows them in standard range, and the web as the browser does by default (usually HDR). Android shows them in standard range. On the web it's CSS's dynamic-range-limit.
Platforms: Android, iOS, tvOS, Web · Type: number · Default: 0
Blurs the image by this radius, in points (the same radius looks about the same on iOS and Android). 0 is no blur.
It's for still images, or a radius that changes now and then (e.g. blurring a photo behind a sheet). Each change blurs the image again on the CPU, so don't animate it.
tintColor, the blurred image is tinted.getCachePath and other views of it aren't affected.To animate a blur, or to blur an animated image, use React Native's filter style instead, which the GPU draws: style={{ filter: [{ blur: 6 }] }}. React Native's docs list blur for Android 12+ only; on iOS it's behind an experimental React Native feature flag (enableSwiftUIBasedFilters, SwiftUI-based filters).
Platforms: Android, iOS, tvOS, Web · Type: string
Text that describes the image, as an <img>'s alt: screen readers read it, and on iOS it makes the image an accessibility element.
aria-label and accessibilityLabel take priority over it.alt (alt="") is a decorative image, with no label.Platforms: Android, iOS, tvOS, Web · Type: () => void
Called when the image starts to load.
Platforms: Android, iOS, tvOS · Type: (event: OnProgressEvent) => void
Called while the image downloads, with the bytes loaded so far, the total, and progress (loaded / total, from 0 to 1; the last event has 1). Not called while the total is unknown (a response without a Content-Length).
onProgress={e => console.log(e.nativeEvent.progress)}
Platforms: Android, iOS, tvOS, Web · Type: (event: OnLoadEvent) => void
Called on a successful image fetch. Called with the width and height of the image itself, not of the view (on iOS, in points: an @2x asset reports half its pixel size).
onLoad={e => console.log(e.nativeEvent.width, e.nativeEvent.height)}
Platforms: Android, iOS, tvOS, Web · Type: (event: OnErrorEvent) => void
Called on an image fetching error, with a message describing it (e.g. the HTTP status code). On iOS and Android, a download that gets nothing from the server for 15 seconds fails too (on Android, unless the app's OkHttp client has timeouts of its own).
onError={e => console.log(e.nativeEvent.error)}
Platforms: Android, iOS, tvOS, Web · Type: (result: LoadResult) => void
Called when the image finishes loading, whether it was successful or an error, with the result: { ok: true, width, height } (the image's size, as onLoad gets it) or { ok: false, error } (as onError gets it). TypeScript makes you check ok before reading the size or the error.
<FastImage source={{ uri }} onLoadEnd={(result) => { if (result.ok) setAspectRatio(result.width / result.height) else setFailed(result.error) }} />
Platforms: Android, iOS, tvOS, Web · Type: StyleProp<ImageStyle>
The image's style: View's style props (borderRadius clips the image, and borders inset it, but padding doesn't), and tintColor, as with React Native's Image (the tintColor prop wins).
Platforms: Android, iOS, tvOS, Web · Type: ColorValue
If supplied, changes the color of all the non-transparent pixels to the given color, including the placeholder.
Loads the image again, e.g. to try again after onError. The image showing stays until the new one has loaded (or the placeholder, if it failed), and the events are sent as for a new source. An image in the cache loads from it. In TypeScript, the ref's type is FastImageRef.
const image = useRef<FastImageRef>(null) <FastImage ref={image} source={{ uri }} onError={() => setFailed(true)} /> {failed && ( <Button title="Try again" onPress={() => { setFailed(false) image.current?.reload() }} /> )}
An image with content on top of it: a view that the image fills, with the children on top.
import { FastImageBackground } from 'react-native-fast-image' const Banner = () => ( <FastImageBackground source={{ uri: 'https://example.com/banner.jpg' }} style={{ width: 200, height: 100 }} imageStyle={{ borderRadius: 8 }} > <Text>On top of the image</Text> </FastImageBackground> )
Its own props are below. Of the others, View props (accessibility, focus, testID, layout and touch) go to the view, and FastImage's own (source, objectFit, onLoad, …) go to the image. imageProps puts any prop on the image instead. Its ref is the view's (imageRef is the image's).
Platforms: Android, iOS, tvOS, Web · Type: StyleProp<ViewStyle>
The container's style; the image fills it.
Platforms: Android, iOS, tvOS, Web · Type: StyleProp<ImageStyle>
The image's style.
Platforms: Android, iOS, tvOS, Web · Type: Ref<FastImageRef>
A ref to the image (the FastImage inside).
Platforms: Android, iOS, tvOS, Web · Type: Omit<FastImageProps, 'children' | 'style'>
Props for the image itself, over the others. View props, such as the accessibility props, go to the container otherwise: use this to make the image the accessibility element instead, e.g. imageProps={{ accessible: true, accessibilityLabel: 'A beach' }}.
Platforms: Android, iOS, tvOS, Web · Type: ReactNode
Content shown on top of the image.
Platforms: Android, iOS, tvOS, Web · Parameters: sources: Source[] · Returns: Promise<PreloadResult[]>
Preload images to display later. e.g.
FastImage.preload([ { uri: 'https://example.com/image-1.jpg', headers: { Authorization: 'someAuthToken' }, }, { uri: 'https://example.com/image-2.jpg', headers: { Authorization: 'someAuthToken' }, }, ])
It resolves when all the images have loaded or failed, with a result for each source, in order: { uri, ok: true, width, height } if it loaded, or { uri, ok: false, error } if it didn't (checking ok narrows the type in TypeScript). width and height are the image's size (as in onLoad), which is also a way to find an image's size without showing it. A few sources load at a time (3, or SDWebImagePrefetcher's maxConcurrentPrefetchCount on iOS), so a long list doesn't hold up the images the app is showing, and at low priority unless the source sets priority. It never rejects:
const results = await FastImage.preload(sources) for (const result of results) { if (result.ok) { console.log(result.uri, result.width, result.height) } else { console.warn(result.uri, result.error) } }
Each source's cache applies, as for a view: with web the preload follows the HTTP cache, and with cacheOnly it doesn't download. A cacheOnly preload resolves ok only if the image is cached.
A source with memoryCache: false is only downloaded to the disk cache, without being decoded into memory, and is decoded when it's shown. Use it to preload many images, or large ones, e.g. the next pages of a feed: a decoded photo can take tens of MB of memory. Other sources are decoded too. A view showing a preloaded image loads it from the cache for its own size: it doesn't wait for the network, but it fades in as other images from the disk cache do (see transition's skipOnCacheHit).
await FastImage.preload(photos.map((uri) => ({ uri, memoryCache: false })))
Platforms: Android, iOS, tvOS · Returns: Promise<ClearCacheResult>
Removes every image from the memory cache, e.g. to free memory. They're decoded from the disk cache again when they're next shown. Resolves with { ok: true } once it's done, or { ok: false, error } if it couldn't (Android: Glide failed to start). Never rejects. On the web, it does nothing (the browser manages its cache) and resolves with an error.
Platforms: Android, iOS, tvOS · Returns: Promise<ClearCacheResult>
Removes every image from the disk cache, including the HTTP cache of cache: 'web' images, e.g. when a user logs out. They're downloaded again when they're next shown. There's no way to remove a single image: to load one again after it changed, change its cacheKey. Resolves like clearMemoryCache.
Platforms: Android, iOS, tvOS · Parameters: source: Source · Returns: Promise<CachePathResult>
The path of the source's downloaded file in the disk cache, e.g. to share, save or upload an image without downloading it again. If the file isn't there, it's downloaded first, without decoding the image or keeping it in memory. Resolves with { ok: true, path }, or { ok: false, error } if it can't be downloaded. Never rejects.
const result = await FastImage.getCachePath({ uri: photo.url }) if (result.ok) { await shareFile(`file://${result.path}`) // e.g. with react-native-share }
With cache: 'cacheOnly' it doesn't download: use it to check whether an image is cached. A source with a cacheKey and no uri is only looked up too (there's no url to download from), e.g. for an image whose signed url has expired.
const { ok } = await FastImage.getCachePath({ uri: photo.url, cache: 'cacheOnly', })
headers, cacheKey and priority apply, as for a view. Downloads wait in the same queue as preload's, so they don't hold up the images on screen. If a view or a preload is downloading the same source, getCachePath shares that download instead of downloading the image again (on Android, except with cache: 'web')..0 or .1): copy it with one for APIs that need it.file:// source resolves with its own path. Other local images (require() in a release build, content://) resolve not ok.cache: 'web', Android only keeps the file if the server allows caching it (in an HTTP cache), and returns ok: false otherwise. If the server compressed the image with Content-Encoding (rare for images), that file is compressed. | ||
| ||
|
| | ||
|---|---|---|---|
| | | |
| | ||
| |