Video.js doesn't work in next.js with server side rendering

I'm trying to configure video.js in a next.js project but it doesn't work.

At the beginning of loading the player appears black and disappears suddenly. In the console there is a warning saying the following:

"video.es.js?31bb:228 VIDEOJS: WARN: The supplied element is not included in the DOM"

The player component code is as follows:

import React from 'react';
import videojs from 'video.js';
import 'video.js/dist/video-js.css';

export const ThorPlayer = (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) {
      const videoElement = videoRef.current;

      if (!videoElement) return;

      const player = playerRef.current = videojs(videoElement, options, () => {
        player.log('player is ready');
        onReady && onReady(player);
      });

    // You can update player in the `else` block here, for example:
    } else {
      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.dispose();
        playerRef.current = null;
      }
    };
  }, [playerRef]);

  return (
    <div data-vjs-player>
      <video ref={videoRef} className='video-js vjs-big-play-centered' style={{ width: "800px", height:"400px" }}/>
    </div>
  );
}

export default ThorPlayer;

And the page that implements the component is this:

import React from 'react'
import ThorPlayer from '../../components/_ThorPlayer'

export default function index() {

  const playerRef = React.useRef(null);

  const videoJsOptions = {
    autoplay: true,
    controls: true,
    responsive: true,
    fluid: true,
    sources: [{
      src: 'https://obj-gravscale.zadarazios.com:443/v1/AUTH_f57eb386f52e4dc0bcdf19764aecc205/ct/bl_se.mp4',
      type: 'video/mp4'
    }]
  };

  const handlePlayerReady = (player) => {
    playerRef.current = player;

    // You can handle player events here, for example:
    player.on('waiting', () => {
      player.log('player is waiting');
    });

    player.on('dispose', () => {
      player.log('player will dispose');
    });
  };

  return (
    <>
      <h1>Teste de Player: </h1>
      <ThorPlayer options={videoJsOptions} onReady={handlePlayerReady} />
      <div></div>
    </>
  )
}

Could someone who has already implemented video.js in next.js help me with this problem?

Upvotes: 2

Views: 2686

Answers (1)

raphaelsaunier
raphaelsaunier

Reputation: 309

Are you using React 18 by any chance? I was running into the same problem as you and it was caused by the fact that useEffect fires twice in development mode.

As a workaround until video.js 7.20 is released, you can use the technique described in this comment.

Upvotes: 3

Related Questions