Search code examples
javascriptreactjsmap-functionrerenderreact-memo

Rerender only specific Child Components in JSX map function


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> )
}

Solution

  • 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);