在 YouTube iframe 的“Node”上反应“removeChild”

Jim*_*mmy 2 html javascript youtube-api typescript reactjs

代码沙盒在这里

我有一个渲染 div 的组件,并在安装时将 youtube iframe 插入到该 div 中。我希望能够切换此组件以显示和隐藏它。但是,每当我“隐藏”组件(卸载它)时,我都会收到以下错误消息:

无法在“Node”上执行“removeChild”:要删除的节点不是此节点的子节点。

我怎样才能卸载这个组件?谢谢。

索引.tsx:

import * as React from "react";
import ReactDOM from "react-dom";

declare global {
  interface Window {
    YT: any;
    onYouTubeIframeAPIReady: Function;
  }
}

const YoutubePlayer: React.FC = () => {
  const videoFrameId = "youtube-player-1";
  const onPlayerReady = (event: { [key: string]: any }): void => {
    event.target.playVideo();
  };

  React.useEffect(() => {
    const loadVideo = (): void => {
      new window.YT.Player(videoFrameId, {
        videoId: "5qap5aO4i9A",
        events: {
          onReady: onPlayerReady
        }
      });
    };

    // If not, load the script asynchronously
    if (!window.YT) {
      const tag = document.createElement("script");
      tag.src = "https://www.youtube.com/iframe_api";

      // onYouTubeIframeAPIReady will load the video after the script is loaded
      window.onYouTubeIframeAPIReady = loadVideo;

      const firstScriptTag = document.getElementsByTagName("script")[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
    } else {
      // If script is already there, load the video directly
      loadVideo();
    }
  }, []);

  return <div id={videoFrameId} />;
};

export default YoutubePlayer;

const App: React.FC = () => {
  const [show, setShow] = React.useState<boolean>(false);
  return (
    <>
      <button type="button" onClick={() => setShow(prevState => !prevState)}>
        {show ? "Hide Player" : "Show Player"}
      </button>
      {show && <YoutubePlayer />}
    </>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Run Code Online (Sandbox Code Playgroud)

Cha*_*ase 5

应该是一个非常简单的修复。为玩家提供一个定义的父元素。

{show && <div><YoutubePlayer /></div>}
Run Code Online (Sandbox Code Playgroud)

代替

{show && <YoutubePlayer />}
Run Code Online (Sandbox Code Playgroud)

然后,removeChild 调用应该不会失败。


编辑:或者更好的是,在内部进行,这样调用者就不需要进行包装。

return <div><div id={videoFrameId} /></div>;
Run Code Online (Sandbox Code Playgroud)

代替

return <div id={videoFrameId} />;
Run Code Online (Sandbox Code Playgroud)