Common React performance mistakes


Performance optimization is one of the challenges of a software developer.

It is a big burden when you start to optimize the application after months or years of development

However, the burden can be minimized by following some performance optimization and best practices while writing the code.

At the same time optimization is a "two edged sword" .

Performance-related changes applied incorrectly can even harm performance.

Here I'll explain some things that I've seen and faced in react applications.

React.memo

If you're using react, you'll be aware of this particular HOC. It is mainly used to memoize the whole component.

memozied children

this is a memoized child component that receives handleOnClick as the props . So as per the memoization logic this component should re-render only if any of the props changes rit ?? that's how React.memo works but wait let's create a parent component and check.

Parent memo

perfect so during every onClick trigger in the child component parent state value changes but the props received in the child didn't change, so child component won't re-render since we memoized.

But wait here's where the real issue comes in if you try the above code in any editor or there's a codesandbox below you can see that the React.memo is broken!, child component will re-render for every state change even though the prop is same.

Is something wrong with the React.memo 🤯 ?

Nope ! every time when the parent component re-renders a new instance of the handleOnClick function is created. Hence is leads to break the memoization and re-renders the child component every time.

So, If you just wrap the child component with React.memo there's no assurance that I will just memoize and work.

But cool hook useCallback can come in to help you out ! . Wrap the handleClick function inside the useCallback hook and try the same code React.memo will just work as expected.

callback wrapper

but the above one is also overratted I would say , will explain this why later in the article
play here

Don't use the React.memo in a component that props is frequently changing, it will result to an extensive calculations.

Inline functions

return (
 <div>
  <button onClick={()=>setState(state+1)}>Increment</button>
 </div>
 )

whenever a developer caught this code everyone (including myself 🤩) update the following code and will be like !

const handleIncrement = () => setState(state+1);
return (
 <div>
  <button onClick={handleIncrement}>Increment</button>
 </div>
 )

yeah I've fixed a dam performance issue I going to get 100 performance score in lighthouse.

gif

but inline is acutally fine in this case !! if you have a concern try working with this

useEffect(()=>{
console.log('Executing')
},[setState])

you cannot use a user defined function inside the useEffect if you're using eslint it will warn you !! but the above code will just work fine because react is smart in this case it knows that setState will never change !.

Caution❌ : In-line functions shouldn't be called without arrow functions

<button onClick={handleIncrement()}>Increment</button>

❌ this might result your code to an infinite loop

useCallback

Does it make sense using this hook here??🤔

this is the first question you should think off before use using these performance hooks like useCallback and useMemo .

`useCallback` is used to memoize functions so that they are not recreated on every render. `React.memo` is used to memoize components so that they are not re-rendered on every render. You can use `React.memo` when your component will render quite often, when your component often renders with the same props, or when your component is big enough (contains a decent amount of UI elements) to have props equality check. You can use `useCallback` when you want to memoize a function so that it is not recreated on every render.

If the child component consist of large amount of data or a extensive calculations, the callback function that you're passing can be wrapped up using useCallback .

Remember Even useCallback() returning the same function object, still the inline function is re-created on every re-rendering useCallback() just skips it. So the re-render will be less commutated than using the useCallback here !

The same set of rules can be applied to useMemo too

No comments:

Post a Comment