Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid rerendering child when passing object in props

Let's say I have a performance-optimized component like this one:

const PerformanceComponent = ({style}) => {
     return <View style={style}>...</View>
}

export default React.memo(PerformanceComponent)

and I am using the component inside the parent like this:

{someArray.map((style) => (
    <PerformanceComponent style={style} />
)}

I am passing different objects for style, it can look like this:

const styles = {
    width: 200,
    height: 200
}

Now React.memo will not do the trick because I am passing an object and React will only compare the memoryaddress (I think its called Shallow Compare).

What are my options to avoid unnecessary rerendering (PerformanceComponent), even if the styles-object did not change?

like image 228
mleister Avatar asked Aug 20 '20 09:08

mleister


3 Answers

As other answers said, you need to pass a function as a second parameter to React.memo that will receive the previous prop and the current prop so you can decide if the component should be rerendered or not (just like shouldComponentUpdate lifecycle for class components).

Because comparing an entire object to see if anything changed can be a expensive operation (depending on the object) and because you can have multiple properties, one way to make sure it's efficient is to use lodash _.isEqual.

import { isEqual } from 'lodash'

const PerformanceComponent = ({style}) => {
     return <View style={style}>...</View>
}

export default React.memo(PerformanceComponent, isEqual)

This way you don't have to worry about implementing the isEqual and it also have a good performance.

like image 139
Vencovsky Avatar answered Sep 20 '22 15:09

Vencovsky


You can add to the memo call a second argument which is a function receiving prevProps and nextProps so you can write some logic to compare them and return true if you want to avoid unnecessary rerendering.

More info here https://reactjs.org/docs/react-api.html#reactmemo

like image 30
Daniel Herrero Hernando Avatar answered Sep 17 '22 15:09

Daniel Herrero Hernando


React.memo takes a second argument as comparison function. However, unlike shouldComponentUpdate it should return true to avoid re-rendering (although this is advised against as it can lead to bugs).

You can read more about it here https://reactjs.org/docs/react-api.html#reactmemo

In the comparison function you could either use lodash.isEqual if the object is large, or in your case something like this:

const isEqual = ({style: prevStyle}, {style: currStyle}) => {
  return prevStyle.width === currStyle.width && prevStyle.height == currStyle.height
}

export default React.Memo(PerformanceComponent, isEqual)
like image 29
Josh Avatar answered Sep 20 '22 15:09

Josh