What is the best way to indicate loading while a video is loading on Expo React Native app?

Viewed 3400

I wanted to ask what would be the best way to handle loading for videos on Expo / React Native.

Expo has good documentation on the Video and AV components to handle video / audio: https://docs.expo.io/versions/latest/sdk/video/ https://docs.expo.io/versions/latest/sdk/av/

I've tried two things so far: '

  1. Using posterSource in a Video component. The problem here is that the poster image doesn't format properly.

This is what my Video component looks like:

    const videoStyle = { width: '100%', height: '100%', display: display}; 
    return (
        <Video
            ref={playbackObject}
            source={{uri: source}}
            posterSource={require('path/to/file')}
            rate={1.0}
            volume={1.0}
            isMuted={isMuted}
            resizeMode="cover"
            usePoster={true}
            shouldPlay={shouldPlay}
            onPlaybackStatusUpdate={_onPlaybackStatusUpdate}
            progressUpdateIntervalMillis={50}
            isLooping
            style={videoStyle}
            posterStyle={videoStyle}
        >
        </Video>
    )
  1. I’ve also tried using playbackStatus to see if the video is loaded or buffering and have an activity indicator when the video is loaded or buffering, but because I use states, there is some lag.

My implementation for (2) looks like this:

const [loaded, setLoaded] = useState(false); 

const _onPlaybackStatusUpdate = playbackStatus => {

    if(playbackStatus.isBuffering){  
      if(loaded){
        setLoaded(false); 
      }
    } else {
      if(!loaded){
        setLoaded(true); 
      }
    }
}

If loaded = true, we do not show an activity indicator. Else, we do show an activity indicator. The main problem here is there is a lag, which is not great UI.

So with that in mind, what would be people’s recommendation of handling loading for videos? Thanks!!

2 Answers

What you can do is to render an <ActivityIndicator /> as background and when it finishes loading the asset, it will get behind the video (or you could just check if the asset was loaded or not -> optionally rendering it inside <Video />.

<Video
  ref={handleVideoRef}
>
  <ActivityIndicator size="large" />
</Video>

  const handleVideoRef = async component => {
    const playbackObject = component;
    if (playbackObject) {
      await playbackObject.loadAsync(
        { uri: currentVideoURI },
      );
    }
  };

here's my solution for that : Video component has onLoadStart and onReadyForDisplay props, which indicate when the loading starts and when it's finished. So we could create a custom component, which would support loading indicator using the Video component imported from expo. So in the end, this would looksomething like this :

import React, {useState} from "react";
import { ActivityIndicator } from "react-native";
import { Video } from "expo-av";

const AppVideo = ({style, ...rest}) => {
  return (
    <View style={style}>
        {isPreloading &&
            <ActivityIndicator
                animating
                color={"gray"}
                size="large"
                style={{ flex: 1, position:"absolute", top:"50%", left:"45%" }}
            />
        }
        <Video
            {...rest}
            onLoadStart={() => setIsPreloading(true)}
            useNativeControls
            onReadyForDisplay={() => setIsPreloading(false)}
            resizeMode="contain"
            isLooping
        />
    </View>
);
 }


export default AppVideo;
Related