Product
Player
Question
In my React (typescript, next js) app we’re using bitmovin-player-react
. It seems to work well, but I’m having issues accessing the player during development
When the app is running with HMR (Hot Module Replacement), ‘React Strict Mode’ renders every component twice, causing handlePlayerRef
to run twice.
It seems the PlayerAPI
assigned to apiRef
is destroyed, breaking my keyboard event listeners in useEffect
My question is this:
How can I access the active PlayerAPI instance when developing with HMR?
My Player Component
// ... other imports
import 'bitmovin-player/bitmovinplayer-ui.css'
import { PlayerAPI, PlayerConfig, PlayerEvent } from 'bitmovin-player'
import { PropsWithChildren, useEffect, useRef } from 'react'
import { useSourceConfig } from '../../hooks/useSourceConfig'
import '../../styles/player.scss'
export type VideoPlayerProps = PropsWithChildren<{
videoId: string
disabled?: boolean
}>
export default function Player(props: VideoPlayerProps) {
// imported with require for NextJS SSR compatibility
const BitmovinPlayer = require('bitmovin-player-react').BitmovinPlayer
// fetches source
const { source } = useSourceConfig({
videoId: props.videoId,
})
const apiRef = useRef<PlayerAPI | null | undefined>(undefined)
const handlePlayerRef = (player: PlayerAPI) => {
if (!player) {
return
}
apiRef.current = player
//... then we set up controls, conviva
}
// Keyboard Controls -- issue is here
useEffect(() => {
const handlePlayPause = (event: KeyboardEvent) => {
// try to play or pause the video
try {
const isPaused = apiRef?.current?.isPaused()
if (isPaused) {
apiRef?.current?.play()
} else {
apiRef?.current?.pause()
}
} catch (error) {
console.warn('Error pausing video', error)
}
}
const handleKeyboardEvent = (event: KeyboardEvent) => {
switch (event.key) {
case 'Enter':
case 'GamepadA':
handlePlayPause(event)
break
default:
break
}
}
window.addEventListener('keydown', handleKeyboardEvent)
return () => {
window.removeEventListener('keydown', handleKeyboardEvent)
}
}, [])
const config: PlayerConfig = {
key: '[MY PLAYER LICENSE KEY]',
cast: {
enable: true,
},
playback: {
autoplay: true,
muted: true,
},
ui: false,
events: {
[PlayerEvent.Error]: (error: any) => {
console.warn('Player error', error)
},
},
}
if (props?.disabled || !source) {
return <></>
}
// return
return (
<BitmovinPlayer
playerRef={handlePlayerRef}
source={source}
config={config}
className="bitmovinplayer-wrapper"
/>
)
}