I have built a material-ui based UI containing tabs in reactJS. Anytime a tab is selected, the content under that tab reloads which is causing a major performance issue because I am displaying an iFrame under one those tabs. I tried to use React.memo to ensure that the screen does not re-render because there is no change in the props but it still does.
Here is the code -
Code sandbox link
Is there a way, that once the iFrame is loaded for the first time and I switch between tabs, the iframe does not get re-rendered again?
I have built a material-ui based UI containing tabs in reactJS. Anytime a tab is selected, the content under that tab reloads which is causing a major performance issue because I am displaying an iFrame under one those tabs. I tried to use React.memo to ensure that the screen does not re-render because there is no change in the props but it still does.
Here is the code -
Code sandbox link
Is there a way, that once the iFrame is loaded for the first time and I switch between tabs, the iframe does not get re-rendered again?
Share Improve this question edited Apr 8, 2020 at 10:18 Niraj asked Apr 8, 2020 at 9:27 Niraj Niraj 3732 gold badges5 silver badges26 bronze badges 2-
Actually using
useMemo
does not render the ponent twice, HTML reloads the source of your iFrame on ponent mount. I've made a sandbox withuseMemo
and put aconsole.count
there, you can check it's rendered only once codesandbox.io/s/material-demo-5tigs?file=/demo.js – Sabbin Commented Apr 8, 2020 at 9:48 - 1 Thanks Sabbin, but I needed the state of the poent to be maintained after you switch the tab. If we useMemo and start the video in one tab and switch to the other tab and then switch back, the video gets loaded again from beginning. I wanted to avoid that – Niraj Commented Apr 8, 2020 at 11:08
2 Answers
Reset to default 15You check if the value
of the current tab equals the index
of the current tab, and only if they are equal you display the content.
Instead - just keep the content and have the Typography ponent control the visibility of it's content (which you already have, using the hidden
inside the Typography
ponent.
<Typography
ponent="div"
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{<Box p={3}>{children}</Box>}
</Typography>
Note that the content will be rendered, so if you have a lot of content inside/requests to the backend/etc - all of those will be part of your DOM, even if you don't see them.
TypeScript solution:
- Wrap the tab display ponent in a
memo()
function call - Wrap the display ponent with the control logic (
<div style={...}
) - Tab change won't re-render the DOM anymore; size of tab content naturally flows by tab display ponent size. Flushing/update can be triggered by state changes in tab display ponent.
Example code:
const SomeTabDisplayComponent = memo(() => {
return <div>Whatever the tab displays</div>
})
const getVisibilityStyle = (hiddenCondition: boolean): any => {
if (hiddenCondition) {
return {
visibility: 'hidden',
height: 0,
};
}
return {
visibility: 'visible',
height: 'inherit',
};
};
<div style={getVisibilityStyle(value !== index)}>
<SomeTabDisplayComponent />
</div>
This solution has many advantages over the prev. answer. It doesn't use another ponent; doesn't mis-use "Typography" (<p>
tag is not meant to include block content! Doing this is bad for SEO and accessibility etc.; violates web standards.); It doesn't depend on Typography's it's internal "hidden" implementation (if that one changes in the future, the upper solution will break) and it gives full control over when the re-render/DOM flush happens.