I got a React project where I’m using a slider to move between the points, which are basically steps, and depending on which step is chosen it plays the part of the video.
Functionality is there, but I’m having a problem when I go to the previous step (like if you go from 8 to 7), and video not play as I want.
What I want to have is that, let say you are in Display step and you click LED, it should play the video till the idle point of LED and stop, and if you click Display again, it should continue playing LED frame till end frame of it and then go back to Display.
I’m using video-react for this.
So,
I’m calling VideoPlayer component in main component as
<div className={styles.content}>
<VideoPlayer currentComponent={selectedComponent} prevComponent={prevComponent} startTime={frames.find((item) => item.id === selectedComponent).start} endTime={frames.find((item) => item.id === selectedComponent).end} idleTime={frames.find((item) => item.id === selectedComponent).idle} />
</div>
and frames
array is like this:
[
...
{
id: 2,
title: 'Display',
start: 221 / 30,
idle: 266 / 30,
end: 312 / 30,
},
{
id: 3,
title: 'Status LED',
start: 313 / 30,
idle: 358 / 30,
end: 403 / 30,
},
...
]
selectedComponent
is just a value between 1 and 8 depending on which step is chosen in slider.
and my VideoPlayer
component is like following:
Updated: made the reverse functionality, but still having problem to stop the video if currentTime>=idleTime when I go to step 2 from step 3.
import React, { useState, useRef, useEffect } from 'react';
import { Player, ControlBar } from 'video-react';
const VideoPlayer = ({ frames, currentComponent, prevComponent, startTime, endTime, idleTime }) => {
const [currentTime, setCurrentTime] = useState(startTime);
const playerRef = useRef(null);
const [isPlaying, setIsPlaying] = useState(true);
useEffect(() => {
play();
seek(startTime);
}, [startTime]);
useEffect(() => {
if (currentTime >= idleTime) {
pause();
setIsPlaying(false);
}
}, [currentTime]);
const play = () => {
playerRef.current.play();
};
useEffect(() => {
if (currentComponent < prevComponent) {
setIsPlaying(true);
playUntil(frames.find(item => item.id === prevComponent).end);
}
}, [currentTime]);
const playUntil = (time) => { //endTime of previous component
console.log(time, currentTime);
console.log(idleTime);
if (time > currentTime && currentTime <= idleTime && isPlaying) {
playerRef.current.play();
} else {
//pause();
playerRef.current.play();
if (currentTime >= idleTime) {
// pause();
setIsPlaying(false);
}
}
if (time <= currentTime) {
pause();
playerRef.current.play();
playerRef.current.seek(startTime);
}
};
const pause = () => {
playerRef.current.pause();
};
const seek = (seconds) => () => {
playerRef.current.seek(seconds);
};
return (
<Player
ref={playerRef}
autoPlay
startTime={0}
muted={true}
onTimeUpdate={(e) => setCurrentTime(parseFloat(e.target.currentTime))}
>
<source src="./video.mp4" style={{ height: '100vh' }} />
<ControlBar autoHide={false} disableCompletely={true} disableDefaultControls={true} />
</Player>
);
};
export default VideoPlayer;
So, to conclude, I’m trying to have a functionality that depending on which selectedComponent
is selected, it should run video till idle
and if user clicks next one, it should continue playing (that functionality is there), if user clicks previous one, it should play till end
frame of the current component and then use seek()
function to go to the start point of previous frame.
I’m also sharing CodeSandbox link for the reference.
2
Answers
Implementing this functionality requires managing the video playback and seeking behavior in response to the user’s interaction with the slider. Here’s an approach you can take:
Player
component usinguseRef
.useEffect
to subscribe to state changes of thePlayer
and to seek the video when the selected step changes.Here’s an updated version of your
VideoPlayer
component that should meet your requirements:This
VideoPlayer
component does the following:Adjust the
useEffect
dependencies and logic as necessary for your specific use case, as this is a starting point and might require fine-tuning. Also, make sure thatprevComponent
state is being updated correctly in the parent component whenever a new component is selected.To address the issue you’ve described, you need to modify the component’s behavior to continue playing the video until it reaches the
endTime
of theprevComponent
before seeking to thestartTime
of thecurrentComponent
. The following changes to theVideoPlayer
component should help you achieve the desired functionality:In this updated version, when the user navigates back (i.e., the
currentComponent
is less than theprevComponent
), the component sets up an interval to monitor the playback position. Once the playback reaches theendTime
of the previous step, it will clear the interval, pause the video, and seek to thestartTime
of thecurrentComponent
.Ensure you have the right
endTime
for theprevComponent
. This might involve passing theendTime
of theprevComponent
into theVideoPlayer
component, which is not currently accounted for in your existing props.The interval is cleared when the
endTime
is reached to avoid unnecessary checks and when the component is unmounted to prevent memory leaks. Adjust the interval duration (currently 100ms) based on how accurately you want to stop the video.