Properly using cached images

  1. SDK Version: 35
  2. Platforms: iOS

I’m having trouble successfully caching and rendering static images. I cache my static (external) assets according to the docs, but when I use the cached image in an ImageBackground, the image flickers as if it’s being downloaded for the first time. (With some files, it seems like the image is not being cached at all because if I pass in cache: 'only-if-cached', the image doesn’t load. In case it’s relevant, I’m using Firebase Storage to store the external images in my actual app.)

Preloading the assets…

function cacheImages(images) {
  return images.map(image => {
    if (typeof image === 'string') {
      return Image.prefetch(image);
    } else {
      return Asset.fromModule(image).downloadAsync();
    }
  });
}

function cacheFonts(fonts) {
  return fonts.map(font => Font.loadAsync(font));
}

export default class AppContainer extends React.Component {
  state = {
    isReady: false,
  };

  async _loadAssetsAsync() {
    const imageAssets = cacheImages([
      'https://via.placeholder.com/3000/09f/fff.png',
    ]);

    const fontAssets = cacheFonts([FontAwesome.font]);

    await Promise.all([...imageAssets, ...fontAssets]);
  }

  render() {
    if (!this.state.isReady) {
      return (
        <AppLoading
          startAsync={this._loadAssetsAsync}
          onFinish={() => this.setState({ isReady: true })}
          onError={console.warn}
        />
      );
    }

    return (
      <View>
        <AppContainer />
      </View>
    );
  }
}

And then using the cached image…

export default class AppContainer extends Component {
  render() {
    return (
      <ImageBackground
        source={{
         uri: 'https://via.placeholder.com/3000/09f/fff.png',
          // cache: 'only-if-cached',
        }}
        imageStyle={{resizeMode: 'cover'}}
        style={{flex: 1}}
      >
         <View>
           ...stuff
         </View>
      </ImageBackground>
    )
  }
}

What am I doing incorrectly or not understanding?

Hey @nsdub,

Are you pre-loading or using asset bundling? If you’re pre-fetching, you’ll need to make sure the asset is explicitly required in order for the packager to pick it up. One last thing, does this also occur with the Image API or just ImageBackground?

Cheers,
Adam

Hey Adam –

Thanks for the note. I’m pre-fetching with Image.prefetch(image).

I don’t believe I’m doing this. I thought require was only for local assets? Could you share an example of how require would be used for a remote static asset? (In case it’s relevant and not apparent from my original post, I’m prefetching and using the image in different components.)

Same behavior with the <Image> API.

Thanks!

Following up here. Is there other info I can provide that would be useful in diagnosis?

Hey @nsdub,

Upon further review, I’m inclined to believe this is an issue with the Image and ImageBackground APIs rather than with Expo’s asset handling. I would recommend trying to replicate the issue with a vanilla RN project and if you are able to do so, then create a github issue on the React Native repo.

Cheers,
Adam

Thanks Adam!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.