diff --git a/next-cloudinary/src/components/CldVideoPlayer/CldVideoPlayer.tsx b/next-cloudinary/src/components/CldVideoPlayer/CldVideoPlayer.tsx index b327aa43..66b3d406 100644 --- a/next-cloudinary/src/components/CldVideoPlayer/CldVideoPlayer.tsx +++ b/next-cloudinary/src/components/CldVideoPlayer/CldVideoPlayer.tsx @@ -1,4 +1,4 @@ -import React, {useRef, MutableRefObject, useEffect, useId} from 'react'; +import React, {useRef, MutableRefObject, useEffect, useId, useState} from 'react'; import Script from 'next/script'; import Head from 'next/head'; import { CloudinaryVideoPlayer } from '@cloudinary-util/types'; @@ -29,6 +29,8 @@ const CldVideoPlayer = (props: CldVideoPlayerProps) => { } = props; const uniqueId = useId(); + const [isScriptLoaded, setIsScriptLoaded] = useState(false); + const [playerInitialized, setPlayerInitialized] = useState(false); const cloudinaryConfig = getCloudinaryConfig(config); const playerOptions = getVideoPlayerOptions(props, cloudinaryConfig); @@ -53,15 +55,6 @@ const CldVideoPlayer = (props: CldVideoPlayerProps) => { playerClassName = `${playerClassName} ${className}`; } - // Check if the same id is being used for multiple video instances. - const checkForMultipleInstance = playerInstances.filter((id) => id === playerId).length > 1 - if (checkForMultipleInstance) { - console.warn(`Multiple instances of the same video detected on the - page which may cause some features to not work. - Try adding a unique id to each player.`) - } else { - playerInstances.push(playerId) - } const events: Record = { error: onError, @@ -86,14 +79,36 @@ const CldVideoPlayer = (props: CldVideoPlayerProps) => { } /** - * handleOnLoad - * @description Stores the Cloudinary window instance to a ref when the widget script loads + * disposePlayer + * @description Properly dispose of the player instance and clean up */ - function handleOnLoad() { - if ( 'cloudinary' in window ) { + const disposePlayer = () => { + if (playerRef.current?.videojs?.cloudinary) { + playerRef.current.videojs.cloudinary.dispose(); + } + // remove from global instances array + playerInstances = playerInstances.filter((instanceId) => instanceId !== playerId); + playerRef.current = null; + setPlayerInitialized(false); + }; + + /** + * initializePlayer + * @description Initialize the Cloudinary video player + */ + + const initializePlayer = () => { + if (typeof window !== 'undefined' && 'cloudinary' in window && videoRef.current && !playerInitialized) { cloudinaryRef.current = window.cloudinary; + + // dispose any existing player instance first to prevent conflicts + if (playerRef.current) { + disposePlayer(); + } + playerRef.current = cloudinaryRef.current.videoPlayer(videoRef.current, playerOptions); + setPlayerInitialized(true); Object.keys(events).forEach((key) => { if ( typeof events[key] === 'function' ) { @@ -101,16 +116,39 @@ const CldVideoPlayer = (props: CldVideoPlayerProps) => { } }); } + }; + + /** + * handleOnLoad + * @description Stores the Cloudinary window instance to a ref when the widget script loads + */ + + function handleOnLoad() { + setIsScriptLoaded(true); + if ( 'cloudinary' in window ) { + initializePlayer(); + } } + // effect to handle component mounting and cleanup useEffect(() => { + // initialize player if script is already loaded + if (isScriptLoaded && typeof window !== 'undefined' && 'cloudinary' in window) { + initializePlayer(); + } return () => { - playerRef.current?.videojs.cloudinary.dispose(); - playerInstances = playerInstances.filter((id) => id !== playerId) - } + disposePlayer(); + }; }, []); + // effect to handle script loading after mount + useEffect(() => { + if (isScriptLoaded && !playerInitialized && typeof window !== 'undefined' && 'cloudinary' in window) { + initializePlayer(); + } + }, [isScriptLoaded, playerInitialized]); + /** *getPlayerRefs */