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>
)
}