Niraj
Niraj

Reputation: 373

Reactjs material ui prevent re-render tabs on enter

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?

Upvotes: 5

Views: 11038

Answers (2)

kyr0
kyr0

Reputation: 515

TypeScript solution:

  1. Wrap the tab display component in a memo() function call
  2. Wrap the display component with the control logic (<div style={...})
  3. Tab change won't re-render the DOM anymore; size of tab content naturally flows by tab display component size. Flushing/update can be triggered by state changes in tab display component.

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 component; 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.

Upvotes: 2

Dekel
Dekel

Reputation: 62536

You 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 component control the visibility of it's content (which you already have, using the hidden inside the Typography component.

<Typography
  component="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.

Upvotes: 15

Related Questions