I have a React project where I’m having a slider between 0 and 700 and depending on which step is chosen it gets value between 1
and 8
(so 700 is obviously 8).
<div className={styles.slider_container}>
<input type='range' className={styles.slider} step={100} min={0} max={700} value={value} onChange={(e) => setValue(parseInt(e.target.value))} />
</div>
I also have an frames
array which consists of bunch of objects which look like:
const [frames, setFrames] = useState([
{
id: 1,
title: 'Touch',
start: 0,
idle: 5.82,
end: 7.10,
},
{
id: 2,
title: 'Display',
start: 7.11,
idle: 8.5,
end: 10.12,
},
...
];
and I call my VideoPlayer
component as:
<div className={styles.content}>
<VideoPlayer frames={frames} 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>
VideoPlayer
component is just using react-video library to display the video and play/pause/seek through it. and it is just like:
const [currentTime, setCurrentTime] = useState(startTime);
const playerRef = useRef(null);
useEffect(() => {
if (currentTime >= idleTime) {
playerRef.current.pause();
}
}, [currentTime]);
useEffect(() => {
if (prevComponent) {
if (prevComponent < currentComponent) {
const time = (frames.find(item => item.id === prevComponent).end); // endTime of previous component;
if (currentTime <= time) {
playerRef.current.play();
if (time - currentTime <= 0.3) {
playerRef.current.pause();
playerRef.current.seek(startTime);
playerRef.current.play();
}
}
}
}
}, [currentTime, currentComponent]);
useEffect(() => {
if (prevComponent > currentComponent) {
playerRef.current.seek(startTime);
playerRef.current.play();
}
}, [currentComponent]);
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>
It works fine with going forward (I mean from step 2 to step 3 or step 4), but I have a problem in
useEffect(() => {
if (prevComponent > currentComponent) {
playerRef.current.seek(startTime);
playerRef.current.play();
}
}, [currentComponent]);
where if I select a component (or step) 2 after step 3 (if we go back), it should play the video till endTime of the prevComponent
and then just back to startTime
of currentComponent
and continue playing till idleTime
of the currentComponent
.
2
Answers
To achieve the behavior you described where the video should play from the end of the previous component to the start of the current component when moving backward, you can make some modifications to your
VideoPlayer
component. Specifically, you need to update the logic in theuseEffect
that handles moving from a higher component to a lower one.You can do this by calculating the time to play from the end of the previous component to the start of the current component and then continue playing from there. Here’s the modified code:
I would apply the
while
loop toif (prevComponent > currentComponent)
condition, so it would just play the video till the difference betweentime
andcurrentTime
is less or equal to zero, if so, just break out from the loop and then useseek()
function to jump to another frame/time you want.