Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid re-rendering in React when switching between tabs

I have a react application using material-ui to create tabs.

<div className={classes.root}>
  <AppBar position="static">
    <Tabs value={value} onChange={handleChange}>
      <Tab label="Item One" />
      <Tab label="Item Two" />
      <Tab label="Item Three" />
    </Tabs>
  </AppBar>
  {value === 0 && <TabContainer id={1}>Item One</TabContainer>}
  {value === 1 && <TabContainer id={2}>Item Two</TabContainer>}
  {value === 2 && <TabContainer id={3}>Item Three</TabContainer>}
</div>

Edit Material-UI Tabs

The TabContainer is a functional component and does some heavy computation.
Is it possible to prevent TabContainer from re-rendering when switching between tabs?

Update:
Check my answer for a solution with React functional components and css classes.

like image 812
Kiran Mohan Avatar asked Jan 18 '20 07:01

Kiran Mohan


People also ask

How do I stop unwanted re-rendering in React?

1. Memoization using useMemo() and UseCallback() Hooks. Memoization enables your code to re-render components only if there's a change in the props. With this technique, developers can avoid unnecessary renderings and reduce the computational load in applications.

How do I stop Rerender rendering in React when state changes?

Preventing Re-Renders: The Old Way To prevent the render method from being called, set the return to false, which cancels the render. This method gets called before the component gets rendered. Sometimes you may want to prevent re-render even if a component's state or prop has changed.

How do I stop infinite rendering in React JS?

To get rid of your infinite loop, simply use an empty dependency array like so: const [count, setCount] = useState(0); //only update the value of 'count' when component is first mounted useEffect(() => { setCount((count) => count + 1); }, []); This will tell React to run useEffect on the first render.

Why is my React page rendering twice?

The reason why this happens is an intentional feature of the React. StrictMode . It only happens in development mode and should help to find accidental side effects in the render phase.


2 Answers

In order to prevent TabContainer from re-rendering. You have to

  1. Render all TabContainer data at once instead of rendering based on value.
  2. You have to play with CSS and have to display only that tab which is currently active.
  3. Also you can make your component as PureComponent or you can override shouldComponentUpdate() lifecycle method to stop extra re-rendering of your react component.
like image 154
Rahul Jain Avatar answered Oct 05 '22 15:10

Rahul Jain


Update/Partial Solution:
With the below code (based on Rahul Jain's answer) using css classes to display the active TabContainer, the memoized functions seems to be really memoized.

    const useTabContainerStyles = makeStyles((theme: Theme) =>  createStyles({
        root: {
          padding: 8 * 3
        },
        tabcontainerInActive: {
          display: "none"
        }
      })
    );

    function TabContainer(props: TabContainerProps) {
      const styles = useTabContainerStyles({});
      console.log("In TabContainer");
      const doubleValue = useMemo(() => double(props.id), [props.id]);
      return (
        <Typography
          id={props.id.toString()}
          component="div"
          className={classnames(styles.root, {
            [styles.tabcontainerInActive]: !props.active
          })}
        >
          {props.children + " " + doubleValue}
        </Typography>
      );
    }

    export default function SimpleTabs() {
      const classes = useStyles({});
      const [selectedTab, setSelectedTab] = React.useState(0);

      function handleChange(event: React.ChangeEvent<{}>, newValue: number) {
        setSelectedTab(newValue);
      }

      return (
        <div className={classes.root}>
          <AppBar position="static">
            <Tabs value={selectedTab} onChange={handleChange}>
              <Tab label="Item One" />
              <Tab label="Item Two" />
              <Tab label="Item Three" />
            </Tabs>
          </AppBar>
          {/*  */}
          <TabContainer id={0} active={selectedTab === 0}>
            Item One
          </TabContainer>
          <TabContainer id={1} active={selectedTab === 1}>
            Item Two
          </TabContainer>
          <TabContainer id={2} active={selectedTab === 2}>
            Item Three
          </TabContainer>
        </div>
      );
    }
like image 27
Kiran Mohan Avatar answered Oct 05 '22 14:10

Kiran Mohan