Local images are slowly displayed even with preloaded assets

Please provide the following:

  1. SDK Version: 38
  2. Platforms(Android/iOS/web/all): Android

Tested with Android but I suppose this applies to iOS to some extent. I assume this is a long-running problem with React Native Image.

Several images take about 700ms to display, and 200ms for single image. This looks really ugly, now I really understand the purpose of fadeDuration option, even with a fade the app ends up in uncanny valley because this looks anything but native.

This is how this looks with Android Studio emulator, which is the worst case scenario for me because it’s sluggish on my side.

Given an array of image modules:

const imgs = [require('./img001.png), ...];
  1. Image modules provided as Image source (a snack):
<View style={styles.container}>
  <View style={styles.grid}>
    {imgs.map((img, i) => <Image style={styles.logo} source={img} fadeDuration={0} key={i} />)}
  </View>
</View>

Several images appear with different delays (up to 1s):

Image source with require only

  1. Preloaded Asset with uri as Image source and delayed splashscreen (a snack):
const [ready, setReady] = React.useState(true);

React.useLayoutEffect(() => {
  SplashScreen.preventAutoHideAsync()
  .then(() => Promise.all(imgAssets.map(asset => asset.downloadAsync())))
  .then(() => setReady(true))
  .then(() => SplashScreen.hideAsync())
}, []);

return ready && (
  <View style={styles.container}>
    <View style={styles.grid}>
      {imgAssets.map((imgAsset, i) => <Image style={styles.logo} source={{ uri: (imgAsset.localUri || imgAsset.uri) }} fadeDuration={0} key={i} />)}
    </View>
  </View>
);

All images appear with roughly the same delay (~700ms) after a splashscreen:

Image source with preloaded Asset

  1. A splashscreen is disabled after Image onLoadEnd (a snack):
const readyPromise = React.useMemo(() => {
	let resolve;
  const promise = new Promise(r => resolve = r);
  promise.resolve = resolve;
  return promise;
}, []);

const onLoadEnd = React.useMemo(() => {
  let imgCount = imgs.length;
  return () => {
    if (!--imgCount) readyPromise.resolve();
  };
}, [readyPromise]);

React.useLayoutEffect(() => {
  SplashScreen.preventAutoHideAsync().catch(e => console.error(e))
  .then(() => readyPromise)
  .then(() => SplashScreen.hideAsync()).catch(e => console.error(e))
}, [readyPromise]);

return null || (
  <View style={styles.container}>  
    <View style={styles.grid}>
      {imgs.map((img, i) => <Image style={styles.logo} onLoadEnd={onLoadEnd} source={img} fadeDuration={0} key={i} />)}
    </View>
  </View>
);

Image assets don’t seem to affect loading time. All images appear with no delay but onLoadEnd introduces an excessive delay (>1s).

Notice that splash screen API is ignored in snacks for some reason, 2 and 3 need to be cloned to local project to reproduce how it really works.


I’m interested in displaying local images without a lag to not break a native experience but not sure what are my options.

Is 3 the only way in managed workflow? Is react-native-fast-image the way it’s done in bare workflow?

I’ve learned about oncoming expo-image from here. Can it really help?

Hey @subus,

We recommend bundling your assets into your binary for the best possible loading experience. https://docs.expo.io/guides/offline-support/#bundle-your-assets-inside-your-standalone-binary which will be the best that you can do until expo-image is ready.

Cheers,
Adam

Thanks, Adam. I’m already using default asset bundle settings for the project, "assetBundlePatterns": ["**/*"]. It actually helps in this case because I’ve used copies of the same image so they are deduped, this makes snippet 1 look like 2 in bundled app, a delay is equal for all images.
I’m eager to try expo-image. Are there any highlights on what it can offer in terms of performance?

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