我有一个 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>
);
}
不涉及“记忆”。 *您想要做的是永远不要卸载包含 iframe 的组件(或 iframe 本身),您只想隐藏它
useMemo 被过度使用了,无论如何它在这里不适用
您有 2 个潜在的解决方案:
不要卸载渲染 iframe 的已安装组件 - 而是将其隐藏
在安装“包含它”的组件时使用本机 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
};