首页与我联系

「React Hooks 学习笔记」关于 React.memo 介绍(三)

By 前端达人
Published in 4-React
September 30, 2022
1 min read
「React Hooks 学习笔记」关于 React.memo 介绍(三)

一、开篇

《React Hooks 学习笔记 | State Hook(一)》《React Hooks 学习笔记 | useEffect Hook(二)》这两篇文章里我们分别学习了 State Hook 和 useEffect Hook,从本篇文章起,我们将讨论下如何应用 Hook 其他的函数提升组件的性能。

在 React 应用中,提升组件的性能涉及两个方面,一是减少不必要的渲染,二是减少渲染的时间。React 自身提供了一些可以非必要渲染的工具函数:memo、useMemo 和 useCallback。本篇文章将介绍下如何使用 React.memo。

React.memo 函数用于创建纯组件,对于给定的参数,纯函数始终返回相同的结果,纯组件与此相同,对于给定的属性,纯组件始终渲染相同的输出。换句话说,在传给组件的 props 的属性和值没有发生改变的情况下,它会使用最近一次缓存的结果,而不会进行重新的渲染,实现跳过组件渲染的效果。

接下来,我们来看一个案例,来分析下 React.memo 存在的必要性和应用场景。

二、案例分析

如下图所示,一个通过接口加载数据的产品列表,列表上方有个计数器,点击按钮计数器就+1,如下图所示:

hook案例.png

页面中共两个子组件,产品列表 BigListSingleProduct 这两个,SingleProduct 嵌套在 BigList 内部,示例代码如下:

SingleProduct 组件:

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

BigList 组件:

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

接下来我们来定义 useFetch 函数用来获取数据,示例代码如下:

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

接下来我们继续,引入 useFetch 函数,通过接口地址获取数据,示例代码如下:

const { products } = useFetch(url)

然后我们继续来定义 Index 将数据渲染到子组件中,并定义 count 数据状态,通过按钮点击,将其加1,示例代码如下:

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

最后我们在 BigListSingleProduct 函数里分别定义 useEffect 函数来观察,点击计数器按钮,查看两个组件是否重新渲染:

// 在 BigList 组件中添加
useEffect(()=>{
     console.log('产品列表开始加载');
 })

// 在 SingleProduct 组件中添加
useEffect(()=>{
      console.log('单个产品图加载');
  })

到这里我们的代码部分就完了,接下来我们来观察下,点击计数器按钮,控制台会如何输出,如下图所示:

reloadcompnent.gif

从上图我们可以看出,每次 count 的数据状态发生变化,都会导致页面的重新渲染,因此页面相关的组件都会重新渲染加载,因此你会看到组件对应的输出。那该如何解决呢,毕竟接口中的 products 数据没有发生变化,真的没必要重新渲染产品列表和产品图片组件,这时使用 React.memo 则是一个很好的解决方案。

三、使用 `React.memo` 函数

使用 React.memo 十分简单,只需要在组件的最外层调用即可,组件的属性作为参数即可,如果参数不发生变化,组件将不会重新加载,否则将会重新加载,示例代码如下:

const BigList = React.memo(({ products }) => {
 useEffect(()=>{
     console.log('产品列表开始加载');
 })
  return (
    <section className='products'>
      {products.map((product) => {
        return <SingleProduct key={product.id} {...product}></SingleProduct>
      })}
    </section>
  );
});

最后我们来验证下,我们来点击计数器的按钮,看看控制台有没有组件重新渲染的输出,效果如下图所示:

finalhookcase.gif

四、总结

今天的文章分享就到这里,感谢你的阅读。最后我们来做下React.memo 使用总结,希望对你有帮助:

  • 父组件中数据 state(状态)如果发生改变,不受 React.memo 函数保护的子组件将会重新渲染
  • React.memo 会检测 props 属性的改变,来决定组件是否需要进行重新渲染,换言之就是,被React.memo 函数包起来的组件只有本身的 props 被改变之后才会重新渲染。
  • React.memo不是项目中所有的组件都需要缓存。使用的太多反而会起反效果,我们需要选择那些经常被重新渲染的组件进行有选择性的去缓存。

前端达人公众号.jpg

注:本文属于原创文章,版权属于「前端达人」公众号及 qianduandaren.com 所有,未经授权,谢绝一切形式的转载


Tags

reacthook
Previous Article
「短文」如何清空 JavaScript 数组的内容
前端达人

前端达人

专注前端知识分享

Table Of Contents

1
一、开篇
2
二、案例分析
3
三、使用 `React.memo` 函数
4
四、总结

相关文章

「React Hooks 学习笔记」关于Custom Hooks 的使用介绍(八)
October 28, 2022
1 min

前端站点

VUE官网React官网TypeScript官网

公众号:前端达人

前端达人公众号