3

I am mapping through an array, which returns JSX Components for each of the items in the array. During runtime I want to pass down values. If they match the value of the individual items, their individual component gets modified.

I am trying to find a way to achieve this without rerendering all components, which currently happens because the props change

I have tried using shouldComponentUpdate in a class component, but it seems this way I can only compare prevState and prevProps with the corresponding changes. I have further considered useMemo in the Map function, which didnt work, because it was nested inside the map function.

const toParent=[1,2,4,5]

Parent Component:

function parent({ toParent }) {

const [myNumbers] = useState([1,2,3,4, ..., 1000]);

return (
   <div>
      {myNumbers.map((number, index) => (
         <Child toChild = { toParent } number = { number } 
          index= { index } key = { number }/>
      ))}
   </div>
  )
}

Child Component:

function Child({toChild, number, index}){
   const [result, setResult] = useState(() => { return number*index }

   useEffect(()=> {
      if (toChild.includes(number)) {
         let offset = 10
         setResult((prev)=> { return { prev+offset }})
      }
   }, [toChild])

   return ( 
      <div style={{width: result}}> Generic Div </div> )
}
Tobi
  • 363
  • 5
  • 15
  • 2
    You can use React.memo. useMemo is for memoizing values not for components. React.memo is a HOC, something which comes close to shouldComponentUpdate – Pavan Aug 10 '20 at 22:28
  • I used React.Memo as well but I wouldnt know how to compare two properties like in my case without creating an infinite loop – Tobi Aug 10 '20 at 22:29
  • Code is way too contrived. can you write code for your useEffect hook so that it's clear on what you're trying to do. – Pavan Aug 10 '20 at 22:32
  • Its an svg path that is being modified. Its pretty complex as Im working with SMIL and I would rather keep it simple. – Tobi Aug 10 '20 at 22:34
  • I have added a little additional complexity – Tobi Aug 10 '20 at 22:56
  • 1
    `React.memo` Higher Order Component is how you can compare incoming props and "suggest" to the react framework *not* to rerender. `memo` HOC can't cause any infinite loops as it doesn't update state or props. – Drew Reese Aug 10 '20 at 23:19
  • @DrewReese How could I implement comparing two props to one anther in React.memo? Sounds really good! – Tobi Aug 11 '20 at 00:10
  • 1
    Reading the docs is a great place to begin: https://reactjs.org/docs/react-api.html#reactmemo, use the second argument, a custom comparison function that takes previous ***and*** next props. Heed the note though, the comparison function essentially returns the *opposite* of `shouldComponentUpdate`. – Drew Reese Aug 11 '20 at 00:21
  • @DrewReese thanks! That did the job for me! So in fact props can be compared to one another, not just between same props in prevProps and nextProps. You think posting my solution here is a good idea? I am fairly new to posting myself – Tobi Aug 11 '20 at 07:20
  • 1
    If by "post my solution" you mean as an answer to a question, then yes, certainly. – Drew Reese Aug 11 '20 at 07:24

1 Answers1

4

The solution to my problem was using the React.memo HOC and comparing the properties to one another and exporting it as React.memo(Child, propsAreEqual).

Performance

This way other methods like findElementbyId (not recommended in any case) and shouldComponentUpdate to target specific items in a map function can be avoided. Performance is quite good, too. Using this method cut down the rendering time from 40ms every 250ms to about 2 ms.

Implementation

In Child Component:

function Child(){...}
function propsAreEqual(prev, next) {
   //returning false will update component, note here that nextKey.number never changes.
   //It is only constantly passed by props
    return !next.toChild.includes(next.number)

}
export default React.memo(Child, propsAreEqual);

or alternatively, if other statements should be checked as well:

function Child(){...}
function propsAreEqual(prev, next) {

   if (next.toChild.includes(next.number)) { return false }
   else if ( next.anotherProperty === next.someStaticProperty ) { return false }
   else { return true }
  }

export default React.memo(Key, propsAreEqual);
Pavan
  • 985
  • 2
  • 15
  • 27
Tobi
  • 363
  • 5
  • 15