I have a video element that has a ref to use to get it's properties. Pretty standard stuff, I think. The problem is when the effect runs, the video element (in videoRef.current) gets logged and has a duration property of 311, but beneath it where I try to log the duration property itself doesn't work. It logs NaN.
Here's the code relevant to the question.
const Home = () => {
const [videoState, setVideoState] = useState({
playing: false,
currentTime: 0,
volume: "50%",
playbackSpeed: 1,
totalTime: 0,
})
const videoRef = useRef<HTMLVideoElement>(null)
useEffect(() => {
if (videoRef.current) {
console.dir(videoRef.current)
console.log(+videoRef.current.duration)
// console.log(typeof(videoRef.current.duration))
// @ts-ignore
setVideoState((prev) => ({ ...prev, totalTime: videoRef.current.duration }))
}
}, [])
return (
<div className='p-8 bg-red-500 w-full h-full relative'>
<div className='relative w-fit h-fit'>
<video
src={fall}
ref={videoRef}
// onPlaying={handleTimeUpdate}
onTimeUpdate={handleTimeUpdate}
></video>
</div>
)
}
export default Home
the output
and in the video object, there's a figure for duration
I don't get why duration in video object is 311 when logged out but it's NaN when it's logged directly.
I expected the second log to log the duration figures.
You can look at this question => Retrieving HTML5 video duration separately from the file
The issue is that the duration property is available after the metadata has been loaded. You need to wait for it.
try with this useEffect
useEffect(() => {
const handleDurationChange = () => {
if (videoRef.current) {
console.dir(videoRef.current);
console.log(videoRef.current.duration);
setVideoState((prev) => ({ ...prev, totalTime: videoRef.current.duration }));
}
};
if (videoRef.current) {
videoRef.current.addEventListener('durationchange', handleDurationChange);
}
return () => {
if (videoRef.current) {
videoRef.current.removeEventListener('durationchange', handleDurationChange);
}
};
}, []);
To understand, you can copy/paste this snippet in your browser console:
const obj = { a: 1, b: 2 };
console.dir(obj); // => you will see { a: 3, b: 2 } in the browser
console.dir({ ...obj }); // => you will see { a: 1, b: 2 } in the browser
obj.a = 3;
when you pass directly the object the browser kept a reference of it, and if he changes it will show the object mutated (with the new state)
If you want to "capture" the state at the moment of the console.dir you need to pass a copy of the object.