Components – Re-Rendering? | fixes *`

https://blog.bitsrc.io/5-ways-to-avoid-react-component-re-renderings-90241e775b8c

 

 

5 Ways to Avoid React Component Re-Renderings

How to Avoid Unnecessary Re-rendering in React

React components have evolved a long way from their inception. Still, many developers find it hard to fix unnecessary re-renderings. However, there are many approaches out there to avoid this issue.

In this article, I will discuss 5 methods to avoid unnecessary re-renderings in React components.

1. Memoization using useMemo() and UseCallback() Hooks

Memoization enables your code to re-render components only if there’s a change in the props. With this technique, developers can avoid unnecessary renderings and reduce the computational load in applications.

React provides two Hooks to implement memoization:

  • useMemo()
  • UseCallback()

These Hooks reduce re-renderings by caching and returning the same result if the inputs are the same without any computations. When the inputs change, the cache gets invalidated and the new component state gets rendered.

useMemo()

To understand how we can use the useMemo() Hook, let's consider an example of multiplying 2 numbers.

>const multiply = (x,y) => {
  return x*y
}

The above function will compute the result and re-render the component each time it is called, regardless of the inputs. But, if we use the useMemo() Hook, we can avoid component re-rendering if the inputs are the same and save the result in the cache.

>const cachedValue = useMemo(() => multiply(x, y), [x, y])

Now, the computed result is stored in the cachedValue variable and useMemo() Hook will return it each time unless the inputs are changed.

UseCallback()

UseCallback``() is another React Hook to implement memoization. But, unlike useMemo(), it does not cache the result. Instead, it memoizes the callback function provided to it.

For example, consider a component with a clickable item list.

>import { useCallback } from 'react';export function MyParent({ term }) {  const onClick = useCallback(event => {
    console.log('Clicked Item : ', event.currentTarget);
  }, [item]);  return (
    <Listitem={item} onClick={onClick}
    />
  );
}

In the above example, useCallBack() memoizes the onClick callback. So, it will not re-render the component if the user clicks the same item again and again.

2. API Call Optimization with React Query

It’s common to use the useEffect() Hook for asynchronous data fetching operations in React applications. However, useEffect() runs and fetches data on each render, and in most situations, it keeps loading the same data.

As a solution, we can use the React Query library to cache the response data. When we make an API call, React Query will first return the data from the cache before continuing with the request. Then, it will retrieve the data from the server, and if there is no new data available, it will prevent the component from re-rendering.

>import React from 'react'
import {useQuery} from 'react-query'
import axios from 'axios'async function fetchArticles(){
  const {data} = await axios.get(URL)    
  return data
}function Articles(){
  const {data, error, isError, isLoading } = useQuery('articles', fetchArticles)
 
  if(isLoading){
    return <div>Loading...</div>
  }
  if(isError){
    return <div>Error! {error.message}</div>
  }
  return(
    <div>
      ...
    </div>
  )
}
export default Articles

React Query library has more than 600K weekly NPM downloads and 1.3K+ GitHub Stars.

3. Creating Memoized Selectors with Reselect

Reselect is a third-party React library for creating memorized selectors. It is commonly used with Redux stores and has amazing features to reduce unnecessary re-renderings.

  • Reselect selectors are capable of computing derived data.
  • Reselect selectors do not recompute unless their arguments are changed.
  • They can be used as inputs to other selectors.

Reselect provides an API named createSelector, and it can generate memoized sector functions. For better understanding, let's consider the example given below.

>import { createSelector } from 'reselect' 
...
const selectValue = createSelector(
  state => state.values.value1,
  state => state.values.value2,
  (value1, value2) => value1 + value2
)
...

Here, the createSelector takes 2 selectors as the input and returns the memoized version. Selectors will not be computed again with this memoized version until the values are changed.

Reselect library has more than 2 Million weekly NPM downloads and 18.4K+ GitHub stars.

4. Replace useState() with useRef()

useState() Hook is widely used in React applications to re-render the components on state changes. However, there are scenarios where we need to track state changes without re-rendering the components.

But, if we use the useRef() Hook, we can track the state changes without causing component re-renderings.

>function App() {
  const [toggle, setToggle] = React.useState(false)
  const counter = React.useRef(0)
  console.log(counter.current++)
  return (
    <button onClick={() => setToggle(toggle => !toggle)} > 
      Click 
    </button>
  )
}
ReactDOM.render(<React.StrictMode><App /></React.StrictMode>, document.getElementById('mydiv'))

The above example has a toggle that re-renders the component each time the value changes. But the counter persists its value since it is a mutable ref. Since we are using useRef(), it will only cause a single render. However, if we use useState(), it will cause 2 renders for each toggle.

5. Using React Fragments

If you have worked with React before, you will know that React requires wrapping the components with a single parent element. Though it’s not directly about re-rendering, have you known that it affects the overall component rendering time?

As a solution, you can use React Fragments to wrap the components, and it will reduce the load on the DOM, resulting in faster rendering times and decreased memory usage.

>const App= () => {
  return (
    <React.Fragment><p>Hello<p/><p>World<p/></React.Fragment>
  );
};
Scroll to Top