Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Javascript errors when used in React app #37

Open
alexplumb opened this issue Jul 27, 2021 · 5 comments
Open

Javascript errors when used in React app #37

alexplumb opened this issue Jul 27, 2021 · 5 comments

Comments

@alexplumb
Copy link

Minimal code repro: https://codesandbox.io/s/wonderful-almeida-ncwye?file=/src/App.js

When implementing the mux videojs-kit in a React app using react-router, I see the following error when unloading a component that contains a video tag:

Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

You can reproduce this issue by clicking between the links Video 1 and Video 2 in the sandbox.

I am able to get around this by using the videojs function exported from @mux/videojs-kit to create the player instance.

@erikpena
Copy link
Contributor

Hey @alexplumb,
I'm having a hard time reproducing the error you're experiencing. I created a simple ReactJS app using CRA and added the necessary dependencies (videojs-mux-kit and react-router) with two pages—

// ./App.jsx

import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";

import '@mux/videojs-kit/dist/index.css';
import VideoOne from './pages/video_1';
import VideoTwo from './pages/video_2';

export default function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li><Link to="/video-1">Video 1</Link></li>
            <li><Link to="/video-2">Video 2</Link></li>
          </ul>
        </nav>
        <Switch>
          <Route path="/video-2"><VideoTwo /></Route>
          <Route path={["/", "/video-1"]}><VideoOne /></Route>
        </Switch>
      </div>
    </Router>
  );
}
// './pages/video_1';

import React from 'react';
// @ts-ignore
import videojs from '@mux/videojs-kit';

const PLAYBACK_ID = 'DS00Spx1CV902MCtPj5WknGlR102V5HFkDe';

export default function VideoOne() {
  const videoRef = React.useRef<HTMLVideoElement|null>(null);

  React.useEffect(() => { videojs(videoRef.current); }, []);

  const options:any = {
    timelineHoverPreviewsUrl: `https://image.mux.com/${PLAYBACK_ID}/storyboard.vtt`,
    plugins: {
      mux: {
        data: { env_key: process.env.REACT_APP_MUX_ENV_KEY }
      }
    }
  };

  return (
    <div>
      <h1>Video 1</h1>
      <div>
        <div>
          <video
            id="mux-default"
            ref={(ref) => videoRef.current = ref}
            className="video-js vjs-16-9"
            controls
            preload="auto"
            width="100%"
            poster={`https://image.mux.com/${PLAYBACK_ID}/thumbnail.jpg`}
            data-setup={JSON.stringify(options)}
          >
            <source src={PLAYBACK_ID} type="video/mux" />
          </video>
        </div>
      </div>
    </div>
  )
};
// ./pages/video_2
import React from 'react';
// @ts-ignore
import videojs from '@mux/videojs-kit';

const PLAYBACK_ID = 'DS00Spx1CV902MCtPj5WknGlR102V5HFkDe';

export default function VideoTwo() {
  const videoRef = React.useRef<HTMLVideoElement|null>(null);

  React.useEffect(() => { videojs(videoRef.current); }, []);

  const options:any = {
    timelineHoverPreviewsUrl: `https://image.mux.com/${PLAYBACK_ID}/storyboard.vtt`,
    plugins: {
      mux: {
        data: { env_key: process.env.REACT_APP_MUX_ENV_KEY }
      }
    }
  };

  return (
    <div>
      <h1>Video 2</h1>
      <div>
        <div>
          <video
            id="mux-default"
            ref={(ref) => videoRef.current = ref}
            className="video-js vjs-16-9"
            controls
            preload="auto"
            width="100%"
            poster={`https://image.mux.com/${PLAYBACK_ID}/thumbnail.jpg`}
            data-setup={JSON.stringify(options)}
          >
            <source src={PLAYBACK_ID} type="video/mux" />
          </video>
        </div>
      </div>
    </div>
  )
};

If you could let me know what your repro looks like so I can start with that, it would help me tremendously. Otherwise, I did also find this comment on Video.js's repo which seems similar to your issue. Maybe this would help you as well?—

videojs/video.js#4935 (comment)

@alexplumb
Copy link
Author

Hi @erikpena,

Thanks for getting back to me so quickly! I linked a minimal code repro in the ticket description. Here's another link, and some steps:

https://codesandbox.io/s/wonderful-almeida-ncwye?file=/src/App.js

It seems there are two problems going on in this repro:

Issue 1 (not the reported issue)

  1. Click on the codesandbox link
  2. Click the link "Video 1"

Expected Outcome:
The video should load and present me with a play button

Actual Outcome:
I see a black video container where the video should bee

Issue 2 (the originally reported issue)

  1. Click on the codesandbox link, or go to https://ncwye.csb.app/video1
  2. Click the link "Video 1"
  3. Click the refresh button in codesandbox
  4. After the page refreshes, click the link "Video 2"

Expected Outcome:
Video 1 should load and present me with a play button. On clicking Video 2, the second video should load and present me with a play button.

Actual Outcome:
Video 1 loads fine, but clicking the link to Video 2 presents a DOM error

Browser:
Windows 10 19043
Brave version 1.27.108 Chromium: 92.0.4515.107

@alexplumb
Copy link
Author

I can confirm that this is still an issue in 0.5.0

@august25
Copy link

@alexplumb I believe this error happens when React does its thing to dispose of the component. You have the video as the top level element, when it attempts to remove the video it sees that it's not the same structure it expects anymore and errors out. This is because the video element is modified by videojs.

The solution is to place the video element in VideoPlayer.tsx into a div so that the parent element is a div instead.

@gkatsev
Copy link
Contributor

gkatsev commented Feb 16, 2022

The recomended approach is to use the "player div ingest" or "<video-js> embed" options of Video.js in react https://docs.videojs.com/tutorial-embeds.html. The Video.js docs have some simple examples on here https://docs.videojs.com/tutorial-react.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants