I have a react application that has components containing iframe. My components do get mounted and unmounted based on a state (e.g. {(showApp === true) && <MyApp/>}
). Every time my component gets mounted, my iframe gets loaded again which do make some additional network calls and results in increased time. Is there a way I can memoize my components that can prevent iframe
from loading again?
Here is a minimal reproducible example of my problem:
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>
);
}
There’s no “memoization” involved. *What you want to do is to never unmount the component containing the iframe (or the iframe itself), you just want to hide it
useMemo is way overused, and it’s not applicable here anyway
You have 2 potential solutions:
Don't unmount the mounted component that renders the iframe - hide it instead
Use native dom methods to append the iframe when the component "containing it" is mounted and toggle the iframe's visibility when the component "containing it" is mounted/unmounted (so it's always in the DOM, just not always visible).
Your current code structure lends itself towards solution 2. This is a rough example with comments to help illustrate the whats and whys. Your precise needs will likely be somewhat different:
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
};