Custom Play Pause buttons – Youtube Iframe

I wanted to implement custom play/pause buttons on youtube iframe in a React project but, couldn’t achieve it! It returns all type of errors like: When I press my custom mute button, it gives: player.mute is not a function and so on.
Here is the code I am using:

var tag = document.createElement("script");
tag.src = "https://www.youtube.com/iframe_api";
  tag.setAttribute("onload", "onYouTubeIframeReady()");
  var firstScriptTag = document.getElementsByTagName("script")[0];
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

  var player;

  window.onYouTubeIframeReady = function () {
    player = new YT.Player("player", {
      videoId: "sGPrx9bjgC8",
      autoplay: true,

      events: {
        onReady: onPlayerReady
      }
    });
  };

  function onPlayerReady(event) {
    event.target.playVideo();
  }

  const playVid = () => {
    player.playVideo();
  };

  const unMuteVid = () => {
    player.unMute();
  };

  const muteVid = () => {
    player.mute();
  };

Here is a CodeSandbox .
Any help is greatly appreciated!

Answer

The root cause

Your code is running inside the App component render.

when doing stuff that needs to modify the DOM or relies on an element rendered by the component being present in the DOM you should use the useEffect hook.

You can in this case move the setup code into a useEffect and set the player using the useState hook.

This way you ensure the iframe is mounted and the references will be right.

see it working here: https://codesandbox.io/s/distracted-murdock-o96u5?file=/src/App.js

const [player, setPlayer] = useState();
  useEffect(() => {
    var tag = document.createElement("script");
    tag.src = "https://www.youtube.com/iframe_api";
    tag.setAttribute("onload", "onYouTubeIframeReady()");
    var firstScriptTag = document.getElementsByTagName("script")[0];
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

    window.onYouTubeIframeReady = function () {
      setPlayer(
        new YT.Player("player", {
          videoId: "sGPrx9bjgC8",
          autoplay: true,

          events: {
            onReady: onPlayerReady
          }
        })
      );
    };

    function onPlayerReady(event) {
      event.target.playVideo();
    }
  }, []);
  
  const playVid = () => {
    console.log(player);
    player.playVideo();
  };

  const unMuteVid = () => {
    player.unMute();
  };

  const muteVid = () => {
    player.mute();
  };

Original answer with a workaround

While I’m still unsure of the root cause, it seems that the new YT.Player is not returning the same object as the one referenced in the onReady event.

One workaround is to just save the event.target reference on the playerReady event to the player variable and use that instead.

function onPlayerReady(event) {
    player = event.target;

here it is working: https://codesandbox.io/s/distracted-dream-n2qmi?file=/src/App.js