React Hooks Study Notes | Introduction to React.memo (3)

1. Opening

exist "React Hooks Study Notes | State Hook (1)" and "React Hooks Study Notes | useEffect Hook (2)" In these two articles, we learned State Hook and useEffect Hook respectively. Starting from this article, we will discuss how to use other functions of Hook to improve the performance of components.

In React applications, improving component performance involves two aspects, one is to reduce unnecessary rendering, and the other is to reduce rendering time. React itself provides some utility functions that can be rendered optional: memo, useMemo and useCallback. This article will introduce how to use React.memo.

React.memo functions are used to create pure components. For a given argument, a pure function always returns the same result. The same goes for a pure component. For a given prop, a pure component always renders the same output. In other words, if the properties and values ​​of the props passed to the component have not changed, it will use the latest cached result without re-rendering to achieve the effect of skipping component rendering.

Next, let's look at a case to analyze the necessity and application scenarios of React.memo.

2. Case Analysis

As shown in the figure below, there is a product list that loads data through the interface. There is a counter at the top of the list, and the counter will be +1 when the button is clicked, as shown in the figure below:

.png

There are two sub-components on the page, the product list BigList and SingleProduct. SingleProduct is nested inside BigList. The sample code is as follows:

SingleProduct component:

const SingleProduct = ({ fields }) => {
  let { name, price } = fields
  price = price / 100
  const image = fields.image[0].url

  return (
    <article className='product'>
      <img src={image} alt={name} />
      <h4>{name}</h4>
      <p>${price}</p>
    </article>
  )
}
copy

BigList component:

const BigList = memo(({ products }) => {
  return (
    <section className='products'>
      {products.map((product) => {
        return <SingleProduct key={product.id} {...product}></SingleProduct>
      })}
    </section>
  );
});
copy

Next, let's define the useFetch function to fetch data. The sample code is as follows:

import { useState, useEffect, useCallback } from 'react';

export const useFetch = (url) => {
  const [loading, setLoading] = useState(true);
  const [products, setProducts] = useState([]);

  const getProducts = useCallback(async () => {
    const response = await fetch(url);
    const products = await response.json();
    setProducts(products);
    setLoading(false);
  }, [url]);

  useEffect(() => {
    getProducts();
  }, [url, getProducts]);
  return { loading, products };
};
copy

Next, let's go ahead and introduce the useFetch function to get data through the interface address. The sample code is as follows:

const { products } = useFetch(url)
copy

Then we continue to define Index to render data into subcomponents, and define the count data state, and add 1 to it by clicking the button. The sample code is as follows:

const url = 'https://course-api.com/javascript-store-products'
const Index = () => {
  const { products } = useFetch(url)
  const [count, setCount] = useState(0)

  return (
    <>
      <h1>Count : {count}</h1>
      <button className='btn' onClick={() => setCount(count + 1)}>
        click me
      </button>
      <BigList products={products} />
    </>
  )
}
copy

Finally, we define the useEffect function in the BigList and SingleProduct functions respectively, to observe, click the counter button to see if the two components re-render:

// In the BigList component add
useEffect(()=>{
     console.log('The product list starts loading');
 })

// In the SingleProduct component add
useEffect(()=>{
      console.log('Single product image loading');
  })
copy

At this point, our code part is over. Next, let's observe how the console will output when the counter button is clicked, as shown in the following figure:

From the above figure, we can see that every time the data state of count changes, the page will be re-rendered, so the page-related components will be re-rendered and loaded, so you will see the corresponding output of the component. How to solve it? After all, the products data in the interface has not changed. There is really no need to re-render the product list and product image components. At this time, using React.memo is a good solution.

3. Using the React.memo function

Using React.memo is very simple, you only need to call it at the outermost layer of the component, and the properties of the component can be used as parameters. If the parameters do not change, the component will not be reloaded, otherwise it will be reloaded. The sample code is as follows:

const BigList = React.memo(({ products }) => {
 useEffect(()=>{
     console.log('The product list starts loading');
 })
  return (
    <section className='products'>
      {products.map((product) => {
        return <SingleProduct key={product.id} {...product}></SingleProduct>
      })}
    </section>
  );
});
copy

Finally, let's verify. Let's click the button of the counter to see if there is any component re-rendered output in the console. The effect is shown in the following figure:

Four. Summary

That's all for today's article sharing, thank you for reading. Finally, let's make a summary of the use of React.memo, hoping to help you:

  • If the data state (state) in the parent component changes, the child component that is not protected by the React.memo function will re-render
  • React.memo will detect the change of the props attribute to determine whether the component needs to be re-rendered. In other words, the component wrapped by the React.memo function will not be re-rendered until its own props are changed.
  • React.memo Not all components in the project need to be cached. Using too much will be counterproductive, we need to select those components that are often re-rendered for selective de-caching.

Tags: React Cache

Posted by adx on Fri, 17 Feb 2023 17:22:22 +1030