Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to prevent extra re-render of child components of a function component react?

I have created a simple Reactjs application. It uses two components a CounterButton and a CounterDisplay. Both are function components.

Both these components are used in another function component FunctionComponent which maintains the state of counter. The problem is that whenever I click on the CounterButton it renders the button again.

In contrast I created another component, ClassComponent which is a class component equivalent to FunctionComponent, and it does not re-render the button on each click.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I understand that the extra render is because I’m using arrow function clickHandler in FunctionComponent, but don’t know how to fix this.

import React from 'react';

const CounterButton = React.memo((props) => {
  console.log(`${props.name} Counter Button Rendered`);
  return (<>
    <button onClick={props.onClick}>{props.name}: Click</button>
    </>)
});
const CounterDisplay = React.memo((props) => {
  console.log('Counter Display Rendered');
  return (<>
    <div>{props.name} : {props.counter}</div>
    </>)
});

function FunctionComponent() {
  const [counter, setCounter] = React.useState(0);

  var clickHandler = () => {
    console.log(">>> FunctionComponent: button clicked <<< ")
    setCounter(counter + 1);
  };
  console.log('---FunctionComponent render---')
  return <>
    <CounterButton name="FunctionComponent" onClick={clickHandler} />
    <CounterDisplay name="FunctionComponent" counter = {counter} />
  </>
}

class ClassComponent extends React.Component {
  state = {
    counter: 0
  };

  clickHandler = () => {
    console.log(">>> ClassComponent: button clicked <<< ")
    this.setState(prev => ({counter: prev.counter + 1}));
  };
  render() {   
    console.log('---ClassComponent render---')
    return <>
      <CounterButton name="ClassComponent" onClick={this.clickHandler} />
      <CounterDisplay name= "ClassComponent" counter = {this.state.counter} />
    </>
  }
}

function App() {
  return <>
    <FunctionComponent/>
    <ClassComponent/>
  </>
}
export default App;

Application starts and I see all components rendered once

---FunctionComponent render---
FunctionComponent Counter Button Rendered
Counter Display Rendered
---ClassComponent render---
ClassComponent Counter Button Rendered
Counter Display Rendered

When I click on the FunctionComponent‘s CounterButton react re-renders the button again.

>>> FunctionComponent: button clicked <<< 
---FunctionComponent render---
FunctionComponent Counter Button Rendered
Counter Display Rendered

When I click on the ClassComponent‘s CounterButton react does not re-render the button again.

>>> ClassComponent: button clicked <<< 
---ClassComponent render---
Counter Display Rendered

I tried using useCallBack for clickHandler, but it didn’t change anything.

  var clickHandler = useCallback(() => {
    console.log(">>> FunctionComponent: button clicked <<< ")
    setCounter(counter + 1);
  },[counter]);

How to achieve the same behavior in FunctionComponent i.e. not re-render button on each click?

>Solution :

I tried using useCallBack for clickHandler, but it didn’t change anything.

 var clickHandler = useCallback(() => {
   console.log(">>> FunctionComponent: button clicked <<< ")
   setCounter(counter + 1);
 },[counter]);

The reason it didn’t change anything is that you’re creating a new click handler every time counter changes. Change your code to use the function version of setState, and remove counter from the dependency array:

const clickHandler = useCallback(() => {
  setCounter(prev => prev + 1);
}, []);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading