Open andreifilip123 opened 1 year ago
👋 Thanks for opening your first issue here! 👋
If you're reporting a 🐞 bug, please make sure you include steps to reproduce it. We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can. To help make it easier for us to investigate your issue, please follow the contributing guidelines.
React 18's strict mode breaks using an element managed by react as the player el with div ingest, so the new recommendation inserts a new el for the player instead. That leaves your adidition components as siblings rather than a child of the player el. There's been occasional discussion of adding a Video.js option to make the standard fullscreen button make a different element fullscreen; this would be a use case for that.
Quickest options would be to insert items into the player DOM after the player has initialised, or replcae the fullscreen button with custom button that makes a different element fulscreen.
Inserting them into the player DOM was my first thought but how would I do that with functional react components ? From the documentation, it seems like it only works with class components or normal html elements (not JSX)
I figured out how to display widgets in the latest version of videojs.
import { FC } from 'react';
interface Options { title: string; description: string; }
const TitleWidget: FC<{ options: Options }> = ({ options: { title, description } }) => { return (
{description}
); };
export default TitleWidget;
2. Next to the component, you create a bridge component
```jsx
import { createRoot } from 'react-dom/client';
import videojs from 'video.js';
import TitleWidget from './TitleWidget';
const VjsComponent = videojs.getComponent('Component');
// @ts-expect-error Videojs types are not working correctly
class TitleWidgetBridge extends VjsComponent {
// @ts-expect-error Videojs types are not working correctly
constructor(player, options) {
super(player, options);
// @ts-expect-error Videojs types are not working correctly
const container = this.el();
const root = createRoot(container);
// When player is ready, mount the React component
player.ready(() => root.render(<TitleWidget options={options} />));
// Unmount the React root when this component is destroyed
// @ts-expect-error Videojs types are not working correctly
this.on('dispose', () => root.unmount());
}
}
export default TitleWidgetBridge;
Important note: Props aren't updated at any later point. So you shouldn't pass state from outside the widget inside and then expect it to change. In case you need to change outside state, it's better to have a function that updates that state outside (while maintaining a copy of it inside the component).
import { FC, useCallback, useEffect, useRef } from 'react';
import videojs from 'video.js';
import Player from 'video.js/dist/types/player';
import 'video.js/dist/video-js.min.css';
import TitleWidgetBridge from './TitleWidget/TitleWidgetBridge';
import './VideoPlayer.scss';
export const CONCEPT_LEARNT_POINTS = 20; export const WATCH_VIDEO_BONUS = 20;
// @ts-expect-error Videojs types are not working correctly videojs.registerComponent('TitleWidget', TitleWidgetBridge);
const playerOptions = { autoplay: true, controls: true, responsive: true, fluid: true, controlBar: { skipButtons: { forward: 10, backward: 10, }, }, bigPlayButton: true, playbackRates: [0.5, 0.8, 1, 1.2, 1.5, 2], sources: [ { src: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4', type: 'video/mp4', }, ], };
const VideoPlayer: FC = () => {
const videoRef = useRef
const handlePlayerReady = useCallback((player: Player) => { player.addChild('TitleWidget', { title: 'Big Buck Bunny', description: 'Big Buck Bunny tells the story of a giant rabbit with a heart bigger than himself.', }); }, []);
useEffect(() => { // Make sure Video.js player is only initialized once if (!playerRef.current) { const videoElement = document.createElement('video-js');
videoElement.classList.add('vjs-custom-skin', 'vjs-big-play-centered', 'vjs-show-big-play-button-on-pause');
videoRef.current?.appendChild(videoElement);
const player = (playerRef.current = videojs(videoElement, playerOptions, () => {
videojs.log('player ready');
// focus on the player so that the hotkeys work
player.focus();
handlePlayerReady(player);
}));
} else {
// You could update an existing player in the `else` block here
// on prop change, for example:
const player = playerRef.current;
if (playerOptions.autoplay) player.autoplay(playerOptions.autoplay);
if (playerOptions.sources) player.src(playerOptions.sources);
}
}, [videoRef]);
// Dispose the Video.js player when the functional component unmounts useEffect(() => { const player = playerRef.current;
return () => {
if (player && !player.isDisposed()) {
player.dispose();
playerRef.current = null;
}
};
}, [playerRef]);
return (
); };
export default VideoPlayer;
I wrote this because when I was building our video player I couldn't find a good guide in the docs on how to integrate videojs with custom made widgets.
Hey! We've detected some video files in a comment on this issue. If you'd like to permanently archive these videos and tie them to this project, a maintainer of the project can reply to this issue with the following commands:
@video-archivist-bot save mwQX4j
Hello, Using the latest docs I'm running into an issue that could be really specific so I'm asking for guidelines if you have any.
In an old app, I had something like this:
and then:
and I used the old docs to create the video. This worked fine and the widgets showed up when going full screen as well.
However, using the new docs, I have something like this:
and then:
The issue I'm encountering is that now, the widgets I added are not showing up anymore when going full screen. After hours of debugging, I figured the issue is that with the new setup (.appendChild), the widgets and the video are not children of the same element (they're not siblings but rather there's one more nesting level between them). The final thing looks something like this:
while in the old one it looked like this:
Any tips on how can I move forward with this? (and sorry if this is not the right place to ask).
Here's a codesandbox with the issue: https://codesandbox.io/s/react-videojs-strictmode-fullscreen-kn45xj
Thank you very much and I hope someone will get to this issue soon! 🙏
Originally posted by @andreifilip123 in https://github.com/videojs/videojs.com/issues/163#issuecomment-1441896417