My goal is to have a page where I show multiple iframes and I switch between them using a TabList component from mui.
What I want is to load each iframe only once to then be able to switch between tabs without having the iframe reloading again.
Here is what I currently do:
function DashViewer(props: any) {
let { slug } = useParams();
const [dashboardEntity, setDashboardEntity] = useState<any | null>(null);
const [displayedEmbedRank, setDisplayedEmbedRank] = useState("0");
const { currentUser } = useAuth();
useEffect(() => {
const initialize = () => {
currentUser.getIdToken(true).then(function (idToken: any) {
fetch("/dashboards/viewer/", {
method: "post",
headers: {
Authorization: idToken,
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({ slug: slug }),
})
.then((response) => response.json())
.then((responseData) => {
setDashboardEntity(responseData.data.dash_infos);
});
});
};
return initialize();
}, []);
const handleChange = (event: React.SyntheticEvent, newValue: string) => {
setDisplayedEmbedRank(newValue);
};
return (
<Stack spacing={0}>
<TabContext value={displayedEmbedRank}>
<Box
sx={{ borderBottom: 0 }}
alignItems="center"
justifyContent="center"
>
<TabList onChange={handleChange} centered>
{dashboardEntity != null &&
dashboardEntity.embeds.authorizations.map(
(embed: any, rank: any) => (
<Tab label={embed.label} value={rank} />
)
)}
</TabList>
</Box>
</TabContext>
{dashboardEntity != null &&
dashboardEntity.embeds.authorizations.map(
(embed: any, rank: any) =>
(rank == displayedEmbedRank && (
<Embed name={dashboardEntity.meta.name} i={rank} hide={false}/>
)
)
)}
{dashboardEntity != null &&
dashboardEntity.embeds.authorizations.map(
(embed: any, rank: any) =>
rank != displayedEmbedRank && (
<Embed name={dashboardEntity.meta.name} i={rank} hide={true}/>
)
)}
</Stack>
);
}
The DashViewer components is where I generate my tabs and show a different Embed (see below) component based on a state controlled by the tabs. I pass a ‘hide=true’ prop on the Embed component
I want to show and false on the others.
function Embed(props: any) {
return (
<div {...(props.hide == true && { style: { display: "none" } })}>
<Iframe name={props.name} i={props.i}/>
</div>
);
}
Embed is basically a wrapper around an Iframe component I made, I use the hide prop to hide the div if necessary.
function Iframe(props:any) {
return (
<iframe
name={`embed-${props.i}`}
frameBorder="0"
scrolling="no"
src={`/dashboards/viewer/${props.name}/${props.i}`}
style={{
display: "block",
background: "#1F3B50",
height: "calc(100vh - 60px)",
width: "calc(100vw - 0px)",
margin: "auto",
border: "none",
}}
></iframe>
)
}
Iframe is very simple it just contains an iframe component.
Currently it switches iframes when I click the different tabs but it always reloads the whole iframe each time.
What I understand is that as displayedEmbedRank is part of the state, each Embed component is re-rendered each time the displayedEmbedRank state changes.
What I tried so far is trying React.memo() on Iframe as I thought it wouldn’t re-render again if it already did for a set of given props, but it didn’t seem to work either.