More optimized way to render multiple videos simultaneously on React Native / Expo?

Viewed 1183

I am working on a video-based app. I am only showing one video at a time but am rendering multiple videos simultaneously.

The reason why I'm rendering multiple videos at a time is so that users can go to one video to a second video without waiting for the second video to load.

I am new to React Native and starting to face performance issues with rendering too many videos. Is there a more optimal way of rendering than the way I'm doing it below?

I can't really tell whether I'm changing data that should be immutable or not avoiding unnecessary re-renders.

I start off by setting a constant renderedVideos.

const renderedVideos = []; 

I have some logic to process some queried data. I ultimately push each video component into the array renderedVideos.

   renderedVideos.push(
      <Video
            ref={playbackObject}
            source={{uri: source}}
            rate={1.0}
            volume={1.0}
            isMuted={isMuted}
            resizeMode="cover"
            usePoster={true}
            shouldPlay={shouldPlay}
            onPlaybackStatusUpdate={_onPlaybackStatusUpdate}
            progressUpdateIntervalMillis={50}
            isLooping
            style={videoStyle}
            >
        </Video>
   ) 

I then call the renderedVideos within a View component.

<View>
   {renderedVideos}
</View>

Is there a more optimal way to render these videos? Thanks so much! If you'd like to see the whole file, please see below :)



import React, { useEffect, useRef, useState } from 'react'; 
import { Video, Audio } from 'expo-av';   
import { View, Animated } from 'react-native';

export default function MultipleVideos(props) {

    const renderedGroup = props.limit; 

    let initialIndex;
    let indexLimit; 

    if (props.first) {
        const renderedIndex = Math.round(props.userIndex / renderedGroup); 
        initialIndex = renderedIndex * renderedGroup;
        indexLimit = renderedIndex * renderedGroup + renderedGroup / 2; 
    } else {
        const renderedIndex = Math.floor(props.userIndex / renderedGroup); 
        initialIndex = renderedIndex * renderedGroup + renderedGroup / 2; 
        indexLimit = renderedIndex * renderedGroup + renderedGroup; 
    }

    const playingData = { 
        isMuted: false, 
        shouldPlay: props.shouldPlay, 
        playbackObject: props.playbackObject, 
        _onPlaybackStatusUpdate: props._onPlaybackStatusUpdate, 
        display: "flex"
    }

    const nonplayingData = {
        isMuted: true, 
        shouldPlay: false, 
        playbackObject: null, 
        _onPlaybackStatusUpdate: null, 
        display: "none"
    }


    useEffect(() => {
        Audio.setAudioModeAsync({
            playsInSilentModeIOS: true
        }); 
    }, []);

    const renderedVideos = []; 

    if(props.videoData) {

        for(let i = initialIndex; i < indexLimit; i++){
            const user = props.videoData.users[i];

            if(user){
                for (let j = 0; j < user.userVideos.length; j++){
                    const muxPlaybackId = user.userVideos[j].muxPlaybackId; 
                    const muxPlaybackUrl = 'https://stream.mux.com/' + muxPlaybackId + '.m3u8';

                    if(props.userIndex == i && props.videoIndex == j){
                        renderedVideos.push(
                            <PlayingVideo
                                key={muxPlaybackId}
                                playbackObject={playingData.playbackObject}
                                source={muxPlaybackUrl}
                                isMuted={playingData.isMuted}
                                shouldPlay={playingData.shouldPlay}
                                _onPlaybackStatusUpdate={playingData._onPlaybackStatusUpdate}
                                display={playingData.display}
                            />
                        )            
                   } 
                    else {
                        renderedVideos.push(
                            <PlayingVideo
                                key={muxPlaybackId}
                                playbackObject={nonplayingData.playbackObject}
                                source={muxPlaybackUrl}
                                isMuted={nonplayingData.isMuted}
                                shouldPlay={nonplayingData.shouldPlay}
                                _onPlaybackStatusUpdate={nonplayingData._onPlaybackStatusUpdate}
                                display={nonplayingData.display}
                            />
                        )    
                    }
                }
            }

        }

    }
    return(
        <View>
            {renderedVideos}
        </View>
    )    
}

function PlayingVideo({playbackObject, source, isMuted, shouldPlay, _onPlaybackStatusUpdate, display}){

    const videoStyle = { width: '100%', height: '100%', display: display}; 
    return(
        <Video
            ref={playbackObject}
            source={{uri: source}}
            // posterSource={{ uri: posterSource}}
            // posterStyle={{ width: '100%', height: '100%', display: display, flex: 1 }}
            rate={1.0}
            volume={1.0}
            isMuted={isMuted}
            resizeMode="cover"
            usePoster={true}
            shouldPlay={shouldPlay}
            onPlaybackStatusUpdate={_onPlaybackStatusUpdate}
            progressUpdateIntervalMillis={50}
            isLooping
            style={videoStyle}
            >
        </Video>
    )
}
0 Answers
Related