discover · compare · collections · requirements · contribute · feed · watching · stats · help with your tokens
DylanVann/react-native-fast-image · source
Snapshot 0 · 2026-11-04T12:47:24Z · TypeScript · MIT
Content fingerprint
b3e9ed65fb114ce211a8298ce69f850938c824b3474e8d878c8060cf778bc0c5GitHub description at capture
Performant React Native image component.
README at capture
# React Native Fast Image
Performant React Native image component.
[![Version][version-badge]][package]
[![Downloads][downloads-badge]][npmtrends]
[![Build Status][build-badge]][build]
[![Docs][docs-badge]][docs]
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:
- Flickering.
- Cache misses.
- Low performance loading from cache.
- Low performance in general.
`FastImage` is an `Image` replacement that solves these issues. `FastImage` is a wrapper around [SDWebImage (iOS)](https://github.com/SDWebImage/SDWebImage) and [Glide (Android)](https://github.com/bumptech/glide).
## Features
- **Performance**: in [benchmarks](docs/benchmarks.md), FastImage shows images about as fast as other React Native image components on iOS and among the fastest on Android, [significantly faster in some scenarios](docs/benchmarks.md#opening-a-photo-while-others-load), and uses among the least memory for large photos.
- **Aggressive caching**: an image downloads once, then shows from disk or memory until its url changes, without flickering ([freshness](#sourcecache), [cache keys](#sourcecachekey), [size limits](#configurecachelimits)).
- **Preloading**, with a [result per image](#preloadsources) and the [cached file's path](#getcachepathsource).
- **Headers**, e.g. for authentication ([`headers`](#sourceheaders)).
- **Priorities** for which images load first ([`priority`](#sourcepriority)).
- **Responsive images**: give several sizes, and the one that fits the view loads ([`source`](#source)).
- **Sized from the image**: a width or height set to `'auto'` follows the loaded image's aspect ratio ([`style`](#style)).
- **Animated images** (GIF, WebP, APNG and AVIF) that can [loop](#loop) and [pause](#paused).
- **Fades** in and between images ([`transition`](#transition)).
- **Placeholders**: a blurred preview from a [ThumbHash](#sourcethumbhash) or a [tiny image](#sourceblurdatauri) while an image loads, a bundled image, or a url, e.g. a thumbnail that's already cached ([`placeholder`](#placeholder)).
- [**SVG**](docs/formats.md#svg-images) and [**photo library**](#photo-library-images-ios-and-tvos) images.
- [**`FastImageBackground`**](#fastimagebackground) for content over an image.
- **Expo and web support**, with a [config plugin](#expo-config-plugin) for Expo.
## Image formats
| Format | iOS | Android |
| ------ | :---------------: | :---------: |
| JPEG | ![Yes][yes] | ![Yes][yes] |
| PNG | ![Yes][yes] | ![Yes][yes] |
| APNG | ![Yes][yes] | ![Yes][yes] |
| GIF | ![Yes][yes] | ![Yes][yes] |
| WebP | ![Yes][yes] | ![Yes][yes] |
| AVIF | ![Yes][yes] | ![Yes][yes] |
| HEIC | ![Yes][yes] | ![Yes][yes] |
| SVG | ![Yes][yes] | ![Yes][yes] |
| ICO | ![Yes][yes] | ![Yes][yes] |
| BMP | ![Yes][yes] | ![Yes][yes] |
| TIFF | ![Yes][yes] | ![No][no] |
| ICNS | ![Yes][yes] | ![No][no] |
| PSD | ![Yes][yes][^psd] | ![No][no] |
See [Formats](docs/formats.md) for the versions of iOS and Android each format needs, and what decodes it.
[yes]: docs/assets/yes.svg
[no]: docs/assets/no.svg
[^psd]: Its composite image (the layers as Photoshop saved them flattened).
## Installation
```bash
npm install react-native-fast-image
cd ios && pod install
```
With Expo:
```bash
npx expo install react-native-fast-image
```
It has native code, so it needs a [development build](https://docs.expo.dev/develop/development-builds/introduction/) (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](https://github.com/react-native-tvos/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](docs/upgrading.md).
To set the cache's size when the app starts, see [Native config](#native-config).
If your Android app has its own Glide `AppGlideModule`, read [using FastImage with an AppGlideModule](docs/android-build-settings.md#if-your-app-has-its-own-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`.
## Usage
```jsx
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"
/>
)
```
## Components
### `FastImage`
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()`](#refreload). It doesn't take children: use [`FastImageBackground`](#fastimagebackground) for content over an image.
<!-- api:props start (generated from src/ by website/scripts/generate.mts) -->
---
#### `source`
**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:
```jsx
<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 },
]}
/>
```
- The view picks once it has been laid out. One that has no size (e.g. sized from `onLoad`) loads the largest.
- When the view's size changes so that another size fits better, it loads that one (with its load events), and keeps showing the current image until then, without a `transition`.
- Each size is cached separately. A `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 }`.
- A `require()`d image can be one of the sizes: its size is the file's.
- An array of one is the same as that source.
---
##### `source.uri`
**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](#photo-library-images-ios-and-tvos)) and SVG images (see [SVG images](docs/formats.md#svg-images)).
---
##### `source.headers`
**Platforms:** Android, iOS, tvOS · **Type:** `{ [key: string]: string }`
Headers to load the image with. e.g. `{ Authorization: 'someAuthToken' }`.
---
##### `source.priority`
**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`.
---
##### `source.cache`
**Platforms:** Android, iOS, tvOS · **Type:** `Cache` · **Default:** `'immutable'`
How fresh the image must be. See [how caching is handled](docs/how-is-caching-handled.md) 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.
---
##### `source.cacheKey`
**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).
```jsx
<FastImage
source={{
uri: signedUrl,
cacheKey: `avatar-${user.id}-${user.avatarUpdatedAt}`,
}}
/>
```
---
##### `source.memoryCache`
**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.
---
##### `source.diskCache`
**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`.
---
##### `source.thumbhash`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `string`
A [ThumbHash](https://evanw.github.io/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](#thumbhashes-on-the-web)).
```jsx
<FastImage source={{ uri: photo.url, thumbhash: photo.thumbhash }} />
```
---
##### `source.blurDataUri`
**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.
```jsx
<FastImage source={{ uri: photo.url, blurDataUri: photo.lqip }} />
```
---
##### `source.width`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `number`
The image's width in points: with `height`, it lays out a side the style leaves out (or sets to `'auto'`) before the image loads (see `style`). With several sources (`source` as an array), the width of the image at this uri, from which the view picks the one for its size.
---
##### `source.height`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `number`
The image's height in points (see `width`).
---
##### `source.scale`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `number`
With several sources, the image's pixels per point at this uri: its size in pixels is `width` and `height` times `scale`. 1 if not given.
---
#### `placeholder`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `string | number | SourcePlaceholder | PlaceholderSource`
A placeholder shown while the image loads, and if it fails to load:
- An image loaded with `require()`: `placeholder={require('./gray.png')}`.
- A data uri: `placeholder="data:image/png;base64,…"`.
- The name of an image bundled with the app (an iOS asset catalog image or an Android drawable): `placeholder="gray"`.
- A [ThumbHash](#sourcethumbhash), shown blurred: `placeholder={{ thumbhash }}`.
- A tiny image as a data uri, shown blurred: `placeholder={{ blurDataUri }}`.
- A url, loaded and cached like a source: `placeholder="https://example.com/placeholder.png"`, or a source with `headers` or a `cacheKey`: `placeholder={{ uri, headers }}`.
- A url only shown if it's already cached, e.g. a list's thumbnail while the full-size image loads: `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:
- On Android, a `require()`d image doesn't show in debug builds, where the dev server serves it. Release builds show it.
- On the web, a url loads like any image, also with `'cacheOnly'`: a browser can't look only in its cache.
---
#### `defaultSource`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `number`
**Deprecated:** Use `placeholder`, which does the same. With both, `placeholder` shows.
---
#### `objectFit`
**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.
---
#### `objectPosition`
**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).
- A string in CSS's syntax: one or two keywords (`'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.
- An object with one of `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.
```jsx
<FastImage source={{ uri }} objectFit="cover" objectPosition="top" />
```
---
#### `recyclingKey`
**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.
```jsx
<FastImage recyclingKey={item.id} source={{ uri: item.imageUrl }} />
```
---
#### `loop`
**Platforms:** Android, iOS, tvOS · **Type:** `number | boolean`
How many times an animated image (GIF, animated WebP, APNG, or animated AVIF) plays:
- Not set: as many times as the file says (like a browser).
- `true`: forever.
- `false`: once.
- A number: that many times.
Changing it restarts the animation.
---
#### `imageRendering`
**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.
---
#### `loading`
**Platforms:** Web · **Type:** `'lazy' | 'eager'` · **Default:** `'lazy'`
Whether the image loads as it nears the screen (`'lazy'`) or at once (`'eager'`).
---
#### `sizes`
**Platforms:** Web · **Type:** `string` · **Default:** `'auto, 100vw'`
With several sources, the width the image is shown at, as the image's [`sizes`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img#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).
---
#### `paused`
**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.
---
#### `transition`
**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.
```jsx
<FastImage source={{ uri }} transition />
<FastImage source={{ uri }} transition={500} />
<FastImage source={{ uri }} transition={{ betweenImages: true, skipOnCacheHit: 'none' }} />
```
---
#### `downsample`
**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.
---
#### `dynamicRangeLimit`
**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`.
---
#### `blurRadius`
**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.
- Only the loaded image is blurred, not a placeholder.
- An animated image (GIF, animated WebP, APNG or AVIF) shows its first frame, blurred, and doesn't animate.
- With `tintColor`, the blurred image is tinted.
- The image is blurred at about the size it's shown at, off the main thread. The cached file stays the original image, so `getCachePath` and other views of it aren't affected.
- Changing it blurs the image that's showing again, without sending the load events again.
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).
---
#### `alt`
**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.
- An empty `alt` (`alt=""`) is a decorative image, with no label.
- On the web, it's the image's alt text.
---
#### `onLoadStart`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `() => void`
Called when the image starts to load.
---
#### `onProgress`
**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`).
```jsx
onProgress={e => console.log(e.nativeEvent.progress)}
```
---
#### `onLoad`
**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).
```jsx
onLoad={e => console.log(e.nativeEvent.width, e.nativeEvent.height)}
```
---
#### `onError`
**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).
```jsx
onError={e => console.log(e.nativeEvent.error)}
```
---
#### `onLoadEnd`
**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.
```jsx
<FastImage
source={{ uri }}
onLoadEnd={(result) => {
if (result.ok) setLoaded(true)
else setFailed(result.error)
}}
/>
```
---
#### `style`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `StyleProp<ImageStyle>`
The image's style: View's style props (`borderRadius` clips the image, and borders inset it; padding is ignored), and `tintColor` (the `tintColor` prop wins).
A width or height set to `'auto'` follows the loaded image:
- `height: 'auto'` with a width (or one from the parent, e.g. stretched in a column): the height from the image's aspect ratio.
- `width: 'auto'` with a height: the width from it (in a row, or with `alignSelf` other than `stretch`: in a column, the parent stretches the width by default).
- Both `'auto'`: the image's own size (a 600 × 300 px image is 600 × 300 points, one of several sources its pixels over its `scale`), at most the space there is. In a column, the parent stretches the width by default, and the height follows it.
Until the image has loaded, and if it fails (`defaultSource` included), those sides are 0, so the layout changes when it loads. A side the style leaves out stays 0: sizing from the image is opt-in, since it moves the layout as images load.
A bundled image, or a source with a `width` and `height` (its size in points), lays out a side the style leaves out (or sets to `'auto'`) from that size at once, keeping its aspect ratio: the layout doesn't change when the image loads.
```jsx
<FastImage source={{ uri }} style={{ width: '100%', height: 'auto' }} />
<FastImage source={{ uri, width: 600, height: 400 }} style={{ width: '100%' }} />
```
---
#### `tintColor`
**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.
<!-- api:props end -->
---
#### `ref.reload()`
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`.
```tsx
const image = useRef<FastImageRef>(null)
<FastImage ref={image} source={{ uri }} onError={() => setFailed(true)} />
{failed && (
<Button
title="Try again"
onPress={() => {
setFailed(false)
image.current?.reload()
}}
/>
)}
```
### `FastImageBackground`
An image with content on top of it: a view that the image fills, with the children on top.
```jsx
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).
<!-- api:background-props start (generated from src/ by website/scripts/generate.mts) -->
---
#### `style`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `StyleProp<ViewStyle>`
The container's style; the image fills it.
---
#### `imageStyle`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `StyleProp<ImageStyle>`
The image's style.
---
#### `imageRef`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `Ref<FastImageRef>`
A ref to the image (the FastImage inside).
---
#### `imageProps`
**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' }}`.
---
#### `children`
**Platforms:** Android, iOS, tvOS, Web · **Type:** `ReactNode`
Content shown on top of the image.
<!-- api:background-props end -->
## Methods
### `preload(sources)`
**Platforms:** Android, iOS, tvOS, Web · **Parameters:** `sources: Source[]` · **Returns:** `Promise<PreloadResult[]>`
Preload images to display later. e.g.
```js
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:
```js
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`).
```js
await FastImage.preload(photos.map((uri) => ({ uri, memoryCache: false })))
```
### `clearMemoryCache()`
**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.
### `clearDiskCache()`
**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`](#sourcecachekey). Resolves like `clearMemoryCache`.
### `getCachePath(source)`
**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.
```js
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.
```js
const { ok } = await FastImage.getCachePath({
uri: photo.url,
cache: 'cacheOnly',
})
```
- The source's `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'`).
- The file belongs to the cache, which can remove it at any time: copy it to keep it.
- Its name may not have an image extension (on Android it ends in `.0` or `.1`): copy it with one for APIs that need it.
- A `file://` source resolves with its own path. Other local images (`require()` in a release build, `content://`) resolve not `ok`.
- A data uri's image is stored in the disk cache, and resolves with that file.
- With `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.
There's no way to remove a single image from the cache. To load an image again after it changed on the server, change its [`cacheKey`](#sourcecachekey).
### `writeToCache(source, file)`
**Platforms:** Android, iOS, tvOS · **Parameters:** `source: Source`, `file: string` · **Returns:** `Promise<CachePathResult>`
Stores a local image file as the source's image in the disk cache, so views and preloads of the source show it without downloading it. For example, after a user uploads a new avatar, store the photo they picked under the avatar's new url or [`cacheKey`](#sourcecachekey), and it shows at once. `file` is a `file://` uri or a path (or on Android a `content://` uri, as image pickers often return). A source with a `cacheKey` doesn't need a `uri`, so the image can be stored before its url is known. Resolves with `{ ok: true, path }` (the cached file) or `{ ok: false, error }`. Never rejects.
```js
const result = await FastImage.writeToCache(
{
uri: user.avatarUrl,
cacheKey: `avatar-${user.id}-${user.avatarUpdatedAt}`,
},
pickedPhoto.uri,
)
```
- The file must be an image.
- It doesn't replace an image that's already cached under the source's key: give a new image a new `cacheKey` (Glide can't replace one on Android).
- Not for `cache: 'web'` sources, which are kept in an HTTP cache.
- Like any cached image, it can be removed from the cache later, and then it's downloaded from the source's url.
### `configureCache(limits)`
**Platforms:** Android, iOS, tvOS · **Parameters:** `limits?: CacheLimits` · **Returns:** `Promise<CacheState>`
How much the image cache keeps. Set the limits your app starts with in its native config, so they're in effect from the first image, and change them while the app runs with `configureCache`, e.g. from a storage setting. Runtime changes are saved, and used on the next launches too.
| Limit | iOS | Android |
| ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `maxDiskSize`: the most bytes of images kept on disk. When it's over, the least recently used images are removed. | Changes apply at once (the cache is trimmed to half the limit). Default: no limit. | Changes apply from the next launch (Glide's disk cache size is set when it starts). Default: 250 MB. |
| `maxDiskAge`: seconds an image is kept on disk after it was last used. | Default: 1 week. | No age limit. |
| `maxMemorySize`: the most bytes of decoded images kept in memory. | Default: no limit (they're removed when the system is low on memory). | About two screenfuls of images.[^glide-memory] |
`0` means no limit.
**Starting limits.** Set them in the app's [native config](#native-config).
**Changing them at runtime.** Pass the limits to change; `null` goes back to the native config's (or the default). It resolves with the limits in effect and `diskSize`, the bytes the image disk cache uses now. Call it without limits to see them.
```js
await FastImage.configureCache({ maxDiskSize: 500 * 1024 * 1024 })
const { maxDiskSize, diskSize } = await FastImage.configureCache()
```
On Android, if your app has its own `AppGlideModule` (see [using FastImage with an AppGlideModule](docs/android-build-settings.md#if-your-app-has-its-own-appglidemodule)), set the disk cache size there instead: `maxDiskSize` isn't applied or reported. Likewise in an app with [expo-image](docs/android-build-settings.md#with-expo-image), whose Glide setup sets the disk cache.
Images with `cache: 'web'` are kept in their own HTTP cache instead, up to 50 MB on each platform, which these limits don't change.
### `setDefaults(defaults)`
**Platforms:** Android, iOS, tvOS · **Parameters:** `defaults: FastImageDefaults` · **Returns:** `void`
Changes the defaults of every image, including `FastImageBackground`'s. Pass the settings to change; `null` goes back to the built-in default.
- `transition`: the [`transition`](#transition) of images that don't set one (its doc describes the built-in default). An image's own `transition` wins, and the settings it leaves out come from the default.
```js
// In index.js, before images render.
FastImage.setDefaults({ transition: false }) // no fades
FastImage.setDefaults({ transition: true }) // fades on iOS too
FastImage.setDefaults({ transition: Platform.select({ ios: 200 }) }) // 200 ms on iOS; Android keeps its default
FastImage.setDefaults({ transition: { duration: 200, betweenImages: true } })
FastImage.setDefaults({ transition: null }) // the built-in default
```
It isn't saved: call it when the app starts. An image already showing uses a change once one of its props changes, for its next load.
## Types
<!-- api:types start (generated from src/ by website/scripts/generate.mts) -->
### `Cache`
**Type:** `'immutable' | 'web' | 'cacheOnly'`
How fresh an image must be: see [`source.cache`](#sourcecache).
---
### `CacheLimits`
`configureCache`'s changes: a number (0 for no limit), or `null` to go back to the app's native config (Info.plist, AndroidManifest.xml) or the platform's default. Leave one out to keep it. Changes are saved, and used on the next launches too. Android only has `maxDiskSize`.
- `maxDiskSize?` (`number | null`): The most bytes of images kept on disk. When it's over, the least recently used are removed (on iOS, until it's half this size). Default: no limit on iOS, 250 MB on Android.
- `maxDiskAge?` (`number | null`): iOS: the seconds an image is kept on disk after it was last used, or 0 to keep them until `maxDiskSize` removes them. Default: 1 week.
- `maxMemorySize?` (`number | null`): iOS: the most bytes of decoded images kept in memory. Default: no limit (they're removed when the system is low on memory).
---
### `CachePathResult`
**Type:** `{ ok: true; path: string } | { ok: false; error: string }`
`getCachePath`'s and `writeToCache`'s result: `ok` with the file's path, or not `ok` with the error.
---
### `CacheState`
`configureCache`'s result: the limits in effect (0 for no limit), and the bytes the disk cache uses now. Android only has `maxDiskSize` and `diskSize`, and neither if the app has its own `AppGlideModule` (or expo-image, which has one).
- `maxDiskSize?` (`number`)
- `maxDiskAge?` (`number`)
- `maxMemorySize?` (`number`)
- `diskSize?` (`number`): The bytes the disk cache uses now.
---
### `ClearCacheResult`
**Type:** `{ ok: true } | { ok: false; error: string }`
`clearMemoryCache`'s and `clearDiskCache`'s result: `ok` once the cache is cleared, or not `ok` with the error.
---
### `FastImageDefaults`
`FastImage.setDefaults`'s settings.
- `transition?` (`number | boolean | Transition | null`): The `transition` of images that don't set one (an image's own settings win, and those it leaves out come from this). `null` goes back to the built-in default (see `transition`).
---
### `LoadResult`
**Type:** `{ ok: true; width: number; height: number } | { ok: false; error: string }`
A load's result, as `onLoadEnd` gets it: `ok` with the image's size, or not `ok` with the error (as `onLoad` and `onError` get them).
---
### `ObjectFit`
**Type:** `'fill' | 'contain' | 'cover' | 'none' | 'scale-down'`
How the image fits the view: see [`objectFit`](#objectfit).
---
### `ObjectPosition`
**Type:** `string | ({ top?: PositionLength; bottom?: never } | { bottom: PositionLength; top?: never }) & ({ left?: PositionLength; right?: never } | { right: PositionLength; left?: never })`
Where the image is in the view: see [`objectPosition`](#objectposition).
---
### `OnErrorEvent`
`onError`'s event: `nativeEvent.error` says what went wrong, e.g. an HTTP status code or an image that can't be decoded.
- `nativeEvent` (`{ error: string }`)
---
### `OnLoadEvent`
`onLoad`'s event: `nativeEvent` has the image's own `width` and `height` (see `onLoad`), and `target`, the view's React tag (on iOS and Android; not on the web).
- `nativeEvent` (`{ width: number; height: number; target?: number }`)
---
### `OnProgressEvent`
`onProgress`'s event: `nativeEvent` has the bytes `loaded` and the `total`, and `progress`, `loaded / total` from 0 to 1.
- `nativeEvent` (`{ loaded: number; total: number; progress: number }`)
---
### `PlaceholderSource`
**Type:** `Pick<Source, 'uri' | 'headers' | 'cacheKey' | 'cache'>`
A url as `placeholder`, loaded like a source (see `placeholder`).
---
### `PositionLength`
**Type:** `` number | `${number}%` ``
A length in points (dp on Android), or a percentage: see [`objectPosition`](#objectposition).
---
### `PreloadFailure`
A preloaded source that failed to load.
- `uri?` (`string`): The source's uri (none for a source without one, e.g. `null`).
- `ok` (`false`)
- `error` (`string`): What went wrong.
---
### `PreloadResult`
**Type:** `PreloadSuccess | PreloadFailure`
`preload`'s result for a source. Check `ok` to tell which it is: e.g. `if (result.ok)` narrows it to a `PreloadSuccess`, with its size. Reading `width` or `error` without checking is a type error.
---
### `PreloadSuccess`
A preloaded source that loaded (and is now cached).
- `uri` (`string`): The source's uri.
- `ok` (`true`)
- `width` (`number`): The image's width (as in `onLoad`).
- `height` (`number`): The image's height (as in `onLoad`).
---
### `Priority`
**Type:** `'low' | 'normal' | 'high'`
An image's load priority: see [`source.priority`](#sourcepriority).
---
### `SourcePlaceholder`
**Type:** `Pick<Source, 'thumbhash' | 'blurDataUri'>`
A `thumbhash` or `blurDataUri` as `placeholder`.
---
### `Transition`
How the image fades in: see [`transition`](#transition).
- `duration?` (`number`): How long the fade takes, in milliseconds; 0 means no fade. Defaults to the default transition's (see `FastImage.setDefaults`) if it fades, otherwise the platform's usual length: 300 ms on Android, 250 ms on iOS.
- `betweenImages?` (`boolean`, default `false`): Also fades between images: a new `source` replacing an image that's showing cross-dissolves from it. Otherwise only an image that appears over nothing (or over a placeholder) fades in, and a new source replaces the image showing at once, once it has loaded.
- `skipOnCacheHit?` (`'none' | 'memory' | 'all' | null`, default `'memory'`): Skips the fade for an image from a cache, so images already loaded show at once, e.g. in a list scrolled back up or a reused row.
- `'memory'`: skips it for images from the memory cache.
- `'all'`: skips it for images from the memory or disk cache too, so images that download fade in, and local files and bundled images usually only the first time (the disk cache usually keeps them too).
- `'none'`: always fades.
On Android, a `cache: 'web'` image from its HTTP cache, without a request, counts as one from the memory cache (these images aren't kept there).
<!-- api:types end -->
## Native config
The cache's limits the app starts with, read from its native projects so they're in effect from the first image. [`configureCache`](#configurecachelimits) says what each one does and its default, and changes them while the app runs. `0` means no limit.
| Limit | Unit | iOS (`Info.plist`) | Android (`AndroidManifest.xml`) |
| --------------- | ------- | ------------------------ | --------------------------------------------- |
| `maxDiskSize` | bytes | `FastImageMaxDiskSize` | `fastimage.MAX_DISK_SIZE` |
| `maxDiskAge` | seconds | `FastImageMaxDiskAge` | No age limit |
| `maxMemorySize` | bytes | `FastImageMaxMemorySize` | About two screenfuls of images[^glide-memory] |
### Expo config plugin
With Expo, FastImage's config plugin sets them, from its options in `app.json` (or `app.config.js`):
```json
"plugins": [["react-native-fast-image", { "maxDiskSize": 209715200, "maxDiskAge": 2592000 }]]
```
It writes the native settings below when Expo generates the native projects (`npx expo prebuild`), so run that again after changing them. An app that keeps its own `ios/` and `android/` projects sets them there instead.
### iOS
In `ios/<App>/Info.plist`:
```xml
<key>FastImageMaxDiskSize</key>
<integer>209715200</integer>
<key>FastImageMaxDiskAge</key>
<integer>2592000</integer>
```
### Android
In `android/app/src/main/AndroidManifest.xml`, inside `<application>`:
```xml
<meta-data android:name="fastimage.MAX_DISK_SIZE" android:value="209715200" />
```
If your app has its own `AppGlideModule` (see [using FastImage with an AppGlideModule](docs/android-build-settings.md#if-your-app-has-its-own-appglidemodule)), set the disk cache size there instead. In an app with [expo-image](docs/android-build-settings.md#with-expo-image), expo-image's Glide setup sets it.
[^glide-memory]: Glide's default, which FastImage keeps: room for two screenfuls of decoded images (2 × the screen's width × height × 4 bytes, about 20 MB on a 1080 × 2400 screen), plus a pool of bitmaps to reuse (one screenful on Android 8 and later, four before). Together they're limited to 40% of the memory Android gives the app (33% on low-memory devices), and both shrink to fit.
## Photo library images (iOS and tvOS)
A photo library url (`ph://<localIdentifier>`, as camera roll libraries give) loads with SDWebImagePhotosPlugin, which FastImage includes.
The app needs access to the photo library, which it has if it got the url from there. A photo library image is decoded at about the view's size, since photos are large and usually shown small; `onLoad` still reports the photo's own size. `FastImage.preload` of a `ph://` source loads the full-size photo (there's no view to size it for), which doesn't make a view's smaller copy load faster, so preloading photo library images usually isn't worth it. `assets-library://` urls aren't supported. On Android, photo pickers give `content://` urls, which load as they are.
## Web
FastImage works on the web with [react-native-web](https://necolas.github.io/react-native-web/) and React 19 or later. Bundlers pick the web version through the package's `browser` field, or the `.web.js` files next to the native ones.
Support is minimal:
- Props that work: `source` (a `uri`, a `require()`d image, or several sizes, with `thumbhash` and `blurDataUri`), `placeholder` (and `defaultSource`), `objectFit`, `objectPosition`, `tintColor`, `blurRadius`, `alt`, `style`, `source.priority`, the web-only `loading` and `sizes`, `onLoadStart`, `onLoad`, `onError`, `onLoadEnd`, and View props such as `testID`, accessibility props, `onLayout` and `pointerEvents`.
- Ignored: `source.headers` (a browser can't send them for an image), `source.cache`, `source.cacheKey`, `source.memoryCache`, `source.diskCache`, `recyclingKey`, `loop`, `imageRendering`, `paused`, `transition`, `downsample` and `onProgress`.
- The image is an `<img>` element that fills the view inside its borders, with `objectFit` and `objectPosition` as its CSS `object-fit` and `object-position`. `tintColor` is an SVG filter and `blurRadius` a CSS `blur()`, and the placeholder is another `<img>`, under the image until it has loaded. A new `source` gets a new `<img>`, so the previous image doesn't stay while it loads (with several sizes, the browser shows it until the new one has loaded).
- In a framework with React Server Components, such as Next.js, FastImage can be rendered from a server component. It's a client component, so its props must be ones a server component can pass (no event handlers).
- Images load lazily unless [`loading`](#loading) is `'eager'`, and `source.priority` `'high'` and `'low'` are the `<img>`'s `fetchpriority`.
- Several sizes are shown with an `<img>` whose `srcset` lists them, with `sizes="auto, 100vw"` (or [`sizes`](#sizes)): the browser loads the one for the width the image is shown at, in device pixels (usually the smallest that's at least as wide). Browsers that don't support `sizes="auto"`, or an image with `loading="eager"`, use the viewport's width.
- `FastImage.preload` loads the images into the browser's cache and resolves with a result per source. `clearMemoryCache`, `clearDiskCache` and `configureCache` resolve without doing anything (the browser manages its cache), and `getCachePath` and `writeToCache` resolve with `{ ok: false, error: 'Not supported on the web' }`.
### ThumbHashes on the web
On the web, a [`thumbhash`](#sourcethumbhash) needs a decoder, which isn't included by default. Import it once:
```js
import 'react-native-fast-image/thumbhash'
```
Or, to show the preview without any JavaScript (e.g. in a server-rendered page), make the hash a [`blurDataUri`](#sourceblurdatauri) on your server:
```js
import { thumbHashToBlurDataUri } from 'react-native-fast-image/thumbhash'
const source = {
uri: photo.url,
thumbhash: photo.thumbhash, // iOS and Android
blurDataUri: thumbHashToBlurDataUri(photo.thumbhash), // the web
}
```
## Jest
With React Native's Jest preset, FastImage renders without any setup, as its native view (`FastImageView`, in snapshots). Its functions need the native module, which Jest doesn't have, so they throw: mock the ones a test calls, e.g.
```js
jest.spyOn(FastImage, 'preload').mockResolvedValue([])
```
## Troubleshooting
If you have any problems using this library try the steps in [troubleshooting](docs/troubleshooting.md) and see if they fix it.
## Development
[Follow these instructions to get the example app running.](docs/development.md)
## Credits
The idea for this modules came from
[vovkasm's](https://github.com/vovkasm)
[react-native-web-image](https://github.com/vovkasm/react-native-web-image)
package.
It also uses Glide and SDWebImage, but didn't have some features I needed (priority, headers).
Thanks to [@mobinni](https://github.com/mobinni) for helping with the conceptualization
## Licenses
- React Native Fast Image - MIT © [Dylan Vann](https://github.com/DylanVann). See the [LICENSE](LICENSE) file.
- [SDWebImage](https://github.com/SDWebImage/SDWebImage) (iOS) - MIT. See its [LICENSE](https://github.com/SDWebImage/SDWebImage/blob/master/LICENSE) file.
- [Glide](https://github.com/bumptech/glide) (Android) - BSD, part MIT and Apache 2.0. See its [LICENSE](https://github.com/bumptech/glide/blob/master/LICENSE) file.
[build-badge]: https://github.com/DylanVann/react-native-fast-image/actions/workflows/ci.yml/badge.svg
[build]: https://github.com/DylanVann/react-native-fast-image/actions/workflows/ci.yml
[docs-badge]: https://img.shields.io/badge/docs-website-blue.svg
[docs]: https://react-native-fast-image.dylanvann.workers.dev
[downloads-badge]: https://img.shields.io/npm/dm/react-native-fast-image.svg
[npmtrends]: http://www.npmtrends.com/react-native-fast-image
[package]: https://www.npmjs.com/package/react-native-fast-image
[version-badge]: https://img.shields.io/npm/v/react-native-fast-image.svg