I get the code from https://videojs.com/guides/react/.
If I update the state, my video rerender and the video start playing from first, how to solve.
Example code:
Videojs code:
import React from 'react';
import videojs from 'video.js';
import 'video.js/dist/video-js.css';
export const VideoJS = (props) => {
const videoRef = React.useRef(null);
const playerRef = React.useRef(null);
const {options, onReady} = props;
React.useEffect(() => {
// Make sure Video.js player is only initialized once
if (!playerRef.current) {
// The Video.js player needs to be _inside_ the component el for React 18 Strict Mode.
const videoElement = document.createElement("video-js");
videoElement.classList.add('vjs-big-play-centered');
videoRef.current.appendChild(videoElement);
const player = playerRef.current = videojs(videoElement, options, () => {
videojs.log('player is ready');
onReady && onReady(player);
});
// You could update an existing player in the `else` block here
// on prop change, for example:
} else {
const player = playerRef.current;
player.autoplay(options.autoplay);
player.src(options.sources);
}
}, [options, videoRef]);
// Dispose the Video.js player when the functional component unmounts
React.useEffect(() => {
const player = playerRef.current;
return () => {
if (player && !player.isDisposed()) {
player.dispose();
playerRef.current = null;
}
};
}, [playerRef]);
return (
<div data-vjs-player>
<div ref={videoRef} />
</div>
);
}
export default VideoJS;
App.js
import React from 'react';
// This imports the functional component from the previous sample.
import VideoJS from './VideoJS'
const App = () => {
const playerRef = React.useRef(null);
const [timestamp,setTimestamp]= useState(0)
const videoJsOptions = {
autoplay: true,
controls: true,
responsive: true,
fluid: true,
sources: [{
src: '/path/to/video.mp4',
type: 'video/mp4'
}]
};
const handlePlayerReady = (player) => {
playerRef.current = player;
// You can handle player events here, for example:
player.on('waiting', () => {
videojs.log('player is waiting');
});
player.on('dispose', () => {
videojs.log('player will dispose');
});
player.on('timeupdate', function(){
setTimestamp (player.currentTime())
});
};
return (
<>
<div>Rest of app here</div>
<VideoJS options={videoJsOptions} onReady={handlePlayerReady} />
<div>Rest of app here</div>
</>
);
}
In the App.js, I update the timestamp in timeupdate listener, I get rerender and video again start playing from first.
Please help me to solve
The video is re-rendering because of the onReady(player) in the Videojs file. onReady is prop which is coming to VideoJS from the App.js file which is handlePlayerReady.
When you try to set the state of timestamp on the App.js file with player.on('timeupdate') function the function runs and the prop value goes to Video js and then it again re-renders because the Videojs is wrapped in useEffect. So instead of passing the data from App.js i did changed some codes.
VideoJS
import React from "react";
import videojs from "video.js";
import "video.js/dist/video-js.css";
export const VideoJS = (props) => {
const videoRef = React.useRef(null);
const playerRef = React.useRef(null);
const { options, setTimestamp1 } = props;
React.useEffect(() => {
// Make sure Video.js player is only initialized once
if (!playerRef.current) {
// The Video.js player needs to be _inside_ the component el for React 18 Strict Mode.
const videoElement = document.createElement("video-js");
videoElement.classList.add("vjs-big-play-centered");
videoRef.current.appendChild(videoElement);
const player = (playerRef.current = videojs(videoElement, options, () => {
player.on("waiting", () => {
videojs.log("player is waiting");
});
player.on("dispose", () => {
videojs.log("player will dispose");
});
player.on("timeupdate", () => {
setTimestamp1(player.currentTime());
});
}));
// You could update an existing player in the `else` block here
// on prop change, for example:
} else {
const player = playerRef.current;
player.autoplay(options.autoplay);
player.src(options.sources);
}
}, []);
// Dispose the Video.js player when the functional component unmounts
React.useEffect(() => {
const player = playerRef.current;
return () => {
if (player && !player.isDisposed()) {
player.dispose();
playerRef.current = null;
}
};
}, [playerRef]);
return (
<div data-vjs-player>
<div ref={videoRef} />
</div>
);
};
export default VideoJS;
App.js
import React,{ useState, useEffect} from 'react';
// This imports the functional component from the previous sample.
import VideoJS from './VideoJS'
const App = () => {
const playerRef = React.useRef(null);
const [timestamp1,setTimestamp1]= useState(null);
const videoJsOptions = {
autoplay: true,
controls: true,
responsive: true,
fluid: true,
sources: [{
src: 'dandelions.mp4',
type: 'video/mp4'
}]
};
return (
<>
<div>{timestamp1}</div>
<VideoJS options={videoJsOptions} setTimestamp1={setTimestamp1}/>
<div>{timestamp1}</div>
</>
);
}
export default App
here you can see i removed onReady function and put the data directly into VideoJs where OnReady was rendering and i am sending the setTimestamp as a prop and changing the value from VideoJs file. So re rendering problem is solved and you can use state value in App.js.