如何在父级卸载后保持 iframe 挂载在 React 中

问题描述 投票:0回答:1

我有一个 React 应用程序,其组件包含 iframe。我的组件确实根据状态进行安装和卸载(例如

{(showApp === true) && <MyApp/>}
)。每次安装我的组件时,我的 iframe 都会再次加载,这确实会进行一些额外的网络调用并导致时间增加。有没有办法可以memoize我的组件来防止
iframe
再次加载?

这是我的问题的最小可重现示例:

const App1 = () => {
  useEffect(() => {
    console.log("App1 mounted");
  }, []);

  return (
    <iframe
      width="100%"
      height="254"
      src="https://www.google.com/webhp?igu=1"
    ></iframe>
  );
};

const App2 = () => {
  useEffect(() => {
    console.log("App2 mounted");
  }, []);

  return (<div style={{ color: "red" }}>This is App2</div>);
};

const appMap = {
  1: <App1 />,
  2: <App2 />,
};

const MyApp = ({ app }) => {
  const Application = useMemo(() => appMap[app], [app]);

  return (
    <div>
      <span>This is MyApp Container:</span>
      {Application}
    </div>
  );
};

export default function App() {
  const [showApp, setShowApp] = useState(null);

  const App = useMemo(() => <MyApp app={showApp} />, [showApp]);

  return (
    <div>
      <div onClick={() => setShowApp("1")}>Show App 1</div>
      <div onClick={() => setShowApp("2")}>Show App 2</div>
      {showApp && App}
    </div>
  );
}
reactjs iframe react-hooks
1个回答
1
投票

不涉及“记忆”。 *您想要做的是永远不要卸载包含 iframe 的组件(或 iframe 本身),您只想隐藏它

useMemo 被过度使用了,无论如何它在这里不适用

您有 2 个潜在的解决方案:

  1. 不要卸载渲染 iframe 的已安装组件 - 而是将其隐藏

  2. 在安装“包含它”的组件时使用本机 dom 方法附加 iframe,并在安装/卸载“包含它”的组件时切换 iframe 的可见性(因此它始终在 DOM 中,只是并不总是可见)。

您当前的代码结构适合解决方案 2。这是一个粗略的示例,带有注释,可帮助说明内容和原因。您的具体需求可能会有所不同:

const IFRAME_ID = "MY_IFRAME_ID"
const getIframe = () => document.getElementById(IFRAME_ID)
const createIframe = (attrs) => {
   const iframe = document.createElement('iframe')
   iframe.id = IFRAME_ID;
   iframe.width = '100%';
   iframe.height = '254';
   iframe.src = 'https://www.google.com/webhp?igu=1'
   return iframe;
}

const App1 = () => {
  useEffect(() => {
     let iframe = getIframe()
     if(iframe) {
        // when this component mounts and the iframe exists, make sure it's visible
        iframe.style.display = 'block';
     } else {
        // when this component mounts and the iframe doesn't yet exist
        // create it and append it to the DOM
        iframe = createIframe(); 
        document.body.appendChild(iframe);
     }

     return () => {
        // when this component unmounts, hide the iframe
        iframe.style.display = 'none';
     }
  }, []);

  return null
};
© www.soinside.com 2019 - 2024. All rights reserved.