DEV Community

Steven Lavine
Steven Lavine

Posted on

How do I play a hidden video within a react app?

I'm learning React by converting a previous jQuery based web app, over to React. However I have hit a snag. I'm trying to get a hidden video to play after x seconds using react-simple-idle-monitor. The I can get the video frame to play, and if I add the controls attribute the video can be played but I work out how to access the video using react.

I have tried using refs, and accessing the document.getElementById('video').

This is my Screensaver component in Screensaver.js

import React, { Component } from 'react';
type Props = {};

export default class Screensaver extends Component<Props> {
  props: Props;

  render() {
    return (
      <div className="screensaver">
        <video muted loop>
          <source
            src="../assets/video/my-video.mp4"
            type="video/mp4"
          />
        </video>
      </div>
    );
  }
}

Here is my render function in App.js

render() {
    return (
      <IdleMonitor
        activeClassName="appActive"
        idleClassName="appIdle"
        timeout={30000}
        onActive={stopScreensaver}
        onIdle={startScreensaver}
      >
        <div className="panels">
          <Home />
          <Screensaver />
        </div>
      </IdleMonitor>
    );
  }

And here are the functions to start and stop the screensaver in actions/screensaver.js

export function startScreensaver() {
   const videoFile = document.getElementById('screensaver-video');
   videoFile[0].play();
}
export function stopScreensaver() {
  const videoFile = document.getElementById('screensaver-video');
  videoFile[0].pause();
  videoFile[0].currentTime = 0;
}

After the timeout triggers, the video container is shown via CSS but the video does not play.

At the moment I get the error that videoFile[0] is undefined.

Oldest comments (3)

Collapse
 
chrisachard profile image
Chris Achard

I don't have any experience with react-simple-idle-monitor, but I'll give it a go.

Generally, you won't ever have to do a document.getElementById in React - instead, let the data (the state) drive that for you.

refs would be ok here (instead of document.getElementById), but I think there might be a better way (though I could be wrong - more info below):

The idea is to use the IdleMonitor to set state in the class, and then use that state to show and/or hide the video, like this:

class MyClass extends React.Component {

constructor(props) {
  super(props)

  this.state = { idle: false }
}

startScreensaver = () => {
  this.setState({ idle: true })
}

stopScreensaver = () => {
  this.setState({ idle: false })
}

render() {
    return (
      <IdleMonitor
        activeClassName="appActive"
        idleClassName="appIdle"
        timeout={30000}
        onActive={stopScreensaver}
        onIdle={startScreensaver}
      >
        <div className="panels">
          <Home />
          { this.state.idle && <Screensaver /> }
        </div>
      </IdleMonitor>
    );
  }

}

So notice that I just set an "idle" state on start or stop, and then use that idle state to "gate" the screensaver from showing up or not at all - and then the screensaver itself can be set to just autoplay, and it won't even be in the DOM until it's set to idle.

The one place this doesn't make sense is if the screensaver is like, a really big file - and so you want it to load up in the dom at the start, and be instantly ready to play. In that case, I would try to think of a way to use the new idle state to set an attribute to play it.

Does that help at all?

Collapse
 
stevenlavine profile image
Steven Lavine

Oh You GENIUS!!!! Thank you very much. Worked like a charm :D

Collapse
 
chrisachard profile image
Chris Achard

Nice!