Caching images in React Native can be easy, even if you are using Expo's managed workflow. The problem many devs run into is that React Native only supports out of the box. caching images on IOS Other popular community packages that work on Android contain native code, and as such don't work with . For this reason, I open-sourced the code I'm using on my latest project. Behold, ! Expo's managed workflow react-native-expo-cached-image Quick Start Install the module: yarn add react-native-expo-cached-image Import the component: CachedImage ; import from 'react-native-expo-cached-image' Use the component in a render() method: <CachedImage isBackground source={{ uri: }} /> 'https://qvault.io/wp-content/uploads/2019/05/QVault-app.png' The CachedImage component has the same props and API as React Native's and components. To use CachedImage as a background image, just pass in the prop: Image ImageBackground isBackground <CachedImage isBackground source={{ uri: }} /> 'https://qvault.io/wp-content/uploads/2019/05/QVault-app.png' What Is It Doing? CachedImage keeps it simple. It downloads the image to the user's local filesystem using the hash of the URI. Then, on subsequent renders and app uses, it loads the image from the filesystem if it exists. This saves the user from using unnecessary data and experiencing slow load times. SHA-256 Tip: In order to bust the cache, you can append a query string or anchor text to the URI. Link to the Github Code As of writing, here is the code, feel free to just copypasta it if you don't want to install the dependency: React, { Component } from ; { View, Image, ImageBackground } from ; * FileSystem from ; * Crypto from ; export { state = { imgURI: } async componentDidMount() { filesystemURI = await .getImageFilesystemKey( .props.source.uri); await .loadImage(filesystemURI, .props.source.uri); } async componentDidUpdate() { filesystemURI = await .getImageFilesystemKey( .props.source.uri); ( .props.source.uri === .state.imgURI || filesystemURI === .state.imgURI) { ; } await .loadImage(filesystemURI, .props.source.uri); } async getImageFilesystemKey(remoteURI) { hashed = await Crypto.digestStringAsync( Crypto.CryptoDigestAlgorithm.SHA256, remoteURI ); `${FileSystem.cacheDirectory}${hashed}`; } async loadImage(filesystemURI, remoteURI) { { metadata = await FileSystem.getInfoAsync(filesystemURI); (metadata.exists) { .setState({ imgURI: filesystemURI }); ; } imageObject = await FileSystem.downloadAsync( remoteURI, filesystemURI ); .setState({ imgURI: imageObject.uri }); } (err) { console.log( , err); .setState({ imgURI: remoteURI }); } } render() { ( <View> { .props.isBackground ? ( <ImageBackground {... .props} source={ .state.imgURI ? { uri: .state.imgURI } : } > { .props.children} </ImageBackground> ) : ( <Image {... .props} source={ .state.imgURI ? { uri: .state.imgURI } : } /> )} </View> ); } } import 'react' import 'react-native' import as 'expo-file-system' import as 'expo-crypto' default class CachedImage extends Component '' const this this this this const this this if this this this return null this this const return try // Use the cached image if it exists const if this return // otherwise download to cache const this catch 'Image loading error:' this return this this this this null this this this this null Thanks For Reading Lane on Twitter: @wagslane Lane on Dev.to: wagslane Follow Qvault: https://qvault.io