Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

126
Views
React functional components in Array.map are always rerendering when getting passed a function as props

I am trying to render multiple buttons in a parent component that manages all child states centrally. This means that the parent stores e.g. the click state, the disabled state for each button in his own state using useState and passes it as props to the childs. Additionally the onClick function is also defined inside of the parent component and is passed down to each child. At the moment I am doing this like the following:

const [isSelected, setIsSelected] = useState(Array(49).fill(false));
...
const onClick = useCallback((index) => {
     const newIsSelected = [...prev];
     newIsSelected[i] = !newIsSelected[i];
     return newIsSelected;
}, []);
...

(In the render function:)

return isSelected.map((isFieldSelected, key) => {
     <React.Fragment key={key}>
          <TheChildComponent
               isSelected={isFieldSelected}
               onClick={onClick}
          />
     </React.Fragment/>
})

To try to prevent the child component from rerendering I am using...

  • ... useCallback to make react see that the onClick function always stays the same
  • ... React.Fragment to make react find a component again because otherwise a child would not have a unique id or sth similar

The child component is exported as:

export default React.memo(TheChildComponent, compareEquality) with

 const compareEquality = (prev, next) => {
      console.log(prev, next);
      return prev.isSelected === next.isSelected;
 }

Somehow the log line in compareEquality is never executed and therefore I know that compareEquality is never executed. I don't know why this is happening either.

I have checked all blogs, previous Stackoverflow questions etc. but could not yet find a way to prevent the child components from being rerendered every time that at least one component executes the onClick function and by doing that updated the isSelected state.

I would be very happy if someone could point me in the right direction or explain where my problem is coming from.

Thanks in advance!

about 4 years ago · Juan Pablo Isaza
2 answers
Answer question

0

This code will actually generate a new onClick function every render, because useCallback isn't given a deps array:

const onClick = useCallback((index) => {
     const newIsSelected = [...prev];
     newIsSelected[i] = !newIsSelected[i];
     return newIsSelected;
});

The following should only create one onClick function and re-use it throughout all renders:

const onClick = useCallback((index) => {
     const newIsSelected = [...prev];
     newIsSelected[i] = !newIsSelected[i];
     return newIsSelected;
}, []);

Combined with vanilla React.memo, this should then prevent the children from re-rendering except when isSelected changes. (Your second argument to React.memo should have also fixed this -- I'm not sure why that didn't work.)

As a side note, you can simplify this code:

     <React.Fragment key={key}>
          <TheChildComponent
               isSelected={isFieldSelected}
               onClick={onClick}
          />
     </React.Fragment/>

to the following:

          <TheChildComponent key={key}
               isSelected={isFieldSelected}
               onClick={onClick}
          />

(assuming you indeed only need a single component in the body of the map).

about 4 years ago · Juan Pablo Isaza Report

0

Turns out the only problem was neither useCallback, useMemo or anything similar.

In the render function of the parent component I did not directly use

return isSelected.map(...)

I included that part from a seperate, very simple component like this:

const Fields = () => {

     return isSelected.map((isFieldSelected, i) => (
       <TheChildComponent
            key={i}
            isSelected={isFieldSelected}
            onClick={onClick}
       />
     ));

};

That is where my problem was. When moving the code from the seperate component Fields into the return statement of the parent component the rerendering error vanished.

Still, thanks for the help.

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!