问题:添加一个新的元素,导致所有子组件重复渲染问题。

期望:子组件不要频繁的渲染,只渲染新增或发生变化数据的子组件。

解决方案:使用memo包囊子组件。

代码:

子组件Cat.js:

import React from 'react';const Cat = ({name})=>{console.log(`Cat init: ${name}`);return <p>{name}</p>
}
export default Cat;

父组件CatList.js:

import React, { useState } from 'react';
import { Button } from 'antd';
import Cat from '../components/demo-cats/Cat'; // 没有使用memo
/*** cat列表-父类* @returns */
const CatList = () => {console.log("cat 父类");const [cats, setCats] = useState(["Cat 1","Cat 2","Cat 3"]);// addconst handleAddCat = () => {setCats([...cats, prompt("请输入cat名字")]);}return (<div><h2>List of Cat</h2>{cats.map((name, index)=>(<Cat key={index} name={name}></Cat>))}<Button onClick={() => handleAddCat()}>Add Cat</Button></div>);
};
export default CatList;

运行结果:

可以看到新增一个New Cat之后,cats数组长度发生了变化,导致父类重新计算state,所有的子组件重新渲染了一次。

解决思路:子组件用 React.memo() 包裹,如果组件在相同 props 的情况下渲染相同的结果,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。

import React, { memo } from 'react';
import { Button } from 'antd';const Cat = ({name, index, edit})=>{console.log(`PureCat init: ${name}`);return <p>{name} <Button onClick={() => edit(index)}>Edit</Button></p>
}
const PureCat = memo(Cat)
export default PureCat;

再次运行结果:

添加一个Memo Cat,只渲染了新增的子元素,不重复渲染之前的子元素。

再来看一个数组对象问题:

把上面cats改成数组对象,结合数组对象再来看一下数组的操作和调函数对子组件渲染的问题。

CatArray.js:

import React, { useState, useRef, useCallback } from 'react';
import { Button, Input } from 'antd';
// import Cat from '../components/demo-cats/Cat';
import Cat from '../components/demo-cats/PureCat';// Cat数组对象 - demo
const CatArray = () => {const [cats, setCats] = useState([{ name: "Cat 1" },{ name: "Cat 2" }, { name: "Cat 3" }]);const refInput = useRef(null)// addconst handleAddCat = () => {var newCat = { name: refInput.current.input.value };setCats([...cats, newCat]);}/*** 属性发生变化,重新计算states* @param {*} index */const edit = (index) => {const catsCopy = [...cats]; //浅拷贝一下// setCats(catsCopy.map((item, key) => key === index ? { ...item, name: "Jony" } : item));catsCopy.splice(index, 1, {...catsCopy[index], name: "Jony"});setCats(catsCopy)}return (<div><h2>Array Object of Cat</h2>{cats.map((item, index) => (<Cat key={index} edit={edit} index={index} name={item.name}></Cat>))}<Input ref={refInput} placeholder="Please input cat name"></Input><Button onClick={() => handleAddCat()}>Add Cat</Button></div>);
};

备注:Cat是使用memo包囊的子组件。

新增一个名字为New Cat的Cat,添加到数组之后,即使memo包囊的子组件PureCat,子组件依然被重复渲染了。为什么?因为cats发生变化,state重新计算,导致父组件重新渲染,导致edit重新生成了新的方法,子组件props中edit发生了变化,导致子组件重新被渲染了。

React相关的知识:

渲染(Render)
Render基于虚拟 DOM 和高效 Diff 算法的完美配合,实现了对 DOM 最小粒度的更新。
react 处理 render 的基本思维模式是每次一有变动就会去重新渲染整个应用。会将 render 函数返回的虚拟 DOM 树与老的进行比较,从而确定 DOM 要不要更新、怎么更新。

何时触发渲染(Render)
组件挂载
setState() 方法被调用 ( 当 setState 传入 null 的时候,并不会触发 render )

使用React.useCallback解决父组件state发生变化,回调函数重新计算的问题。

  /*** useCallback依赖空数组,初始化时调用一次*/const editCallBack = useCallback((index) => {const catsCopy = [...cats]; //浅拷贝一下// setCats(catsCopy.map((item, key) => key === index ? { ...item, name: "Jony" } : item));catsCopy.splice(index, 1, {...catsCopy[index], name: "Jony"});setCats(catsCopy)}, []);

使用useCallback把edit方法包起来,useCallback依赖空数组,初始化时生成子组件依赖的回调函数,回调函数仅在某个依赖项改变时才会更新。

总结
父组件中state(状态)改变,不受memo保护的子组件也会重新渲染
memo会检测props到改变来决定组件是否需要进行重新渲染,换言之就是,被memo函数包起来的组件只有本身的props被改变之后才会重新渲染
memo只能进行浅拷贝来校验决定是否触发重新渲染。所以改变数组(对象)的props时候记得返回一个全新的数组(对象)
memo不是项目中所有的组件都需要包一下。包的太多反而会起反效果,我们需要选择那些经常被重新渲染的组件有选择性的去缓存。

参考链接:

React 中 memo()、useCallback()、useMemo()_Jas555的博客-CSDN博客

react性能优化之memo的作用和memo的坑_工边页字的博客-CSDN博客_reactmemo

React memo使用解决高频组件渲染问题相关推荐

  1. 解决前端组件渲染没更新数据问题

    问题: 使用前端日期控件时 - 数据联动时数据绑定无效问题 现象: 选择A日期,想动态改变B日期数据,只有第一次选择时会动态改变B日期数据,第二次选择A日期时,B日期数据虽已改变,但是页面数据未改变 ...

  2. 不挂载 组件渲染_让你的 React 组件性能跑得再快一点「实践」

    作者:天泽 转发链接:https://www.zoo.team/article/react-render 性能和渲染(Render)正相关 React 基于虚拟 DOM 和高效 Diff 算法的完美配 ...

  3. react memo 和 react.fc的使用

    1.memo 介绍: React.memo 为高阶组件.它与 React.PureComponent 非常相似,但它适用于函数组件,但不适用于 class 组件. 如果你的函数组件在给定相同 prop ...

  4. [react] 路由切换时同一组件无法重新渲染的有什么方法可以解决?

    [react] 路由切换时同一组件无法重新渲染的有什么方法可以解决? componentWillReceiveProps 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但坚持一定很酷 ...

  5. react 中渲染html_如何在React中识别和解决浪费的渲染

    react 中渲染html by Nayeem Reza 通过Nayeem Reza 如何在React中识别和解决浪费的渲染 (How to identify and resolve wasted r ...

  6. react 组件渲染控制

    场景:子组件不进行任何操作,但父组件操作更新将会导致子组件也进行了重新更新 解决重复渲染组件方式: shouldComponentUpdate PureComponent memo  只可以是纯函数 ...

  7. react组件放在数组中_为什么要在函数组件中使用React.memo?

    这里提一下,如果大家看到这个标题有所疑惑的话,可以花点时间看一下本篇文章.反之呢如果是看到标题第一时间就反映出结论的话,就可以去get其他文章的知识点了 那么接下来就不废话了,直接长刀直入,进入正题! ...

  8. react避免子组件渲染_如何与React一起使用正确的方法来避免一些常见的陷阱

    react避免子组件渲染 One thing I hear quite often is "Let's go for Redux" in our new React app. It ...

  9. 为什么要在函数组件中使用React.memo?

    这里提一下,如果大家看到这个标题有所疑惑的话,可以花点时间看一下本篇文章.反之呢如果是看到标题第一时间就反映出结论的话,就可以去get其他文章的知识点了 那么接下来就不废话了,直接长刀直入,进入正题! ...

最新文章

  1. Javascript 中的神器——Promise
  2. pandas 调整显示的行数列数
  3. python编写木马攻击_用Python写一个自动木马程序
  4. 通过项目逐步深入了解Mybatis二
  5. 你的ABAP程序给佛祖开过光么?来试试Jerry这个小技巧
  6. linux下hba卡服务,在Linux下查看FC HBA卡的速率和状态
  7. [多线程学习笔记] 一个线程安全的队列
  8. 多种方法让网络共享资源自动映射
  9. 高数_第6章无穷级数_函数的幂级数展开式_马克劳林级数
  10. 华为数通网络自动化开发学习笔记
  11. 明日书苑:《九成宫醴泉铭》单字放大米字格临帖字帖
  12. 增加Router接口
  13. html中span标签的详细介绍
  14. python模糊查询mongodb_Python札记 -- MongoDB模糊查询
  15. html鼠标悬停超链接(头像、文字)显示提示信息
  16. 自制Darknet Yolo目标快速标注工具
  17. QIIME2进阶二_元数据及数据导入QIIME2
  18. ILRuntime学习——从零开始
  19. JS输入框检验字符数(中文为2个字符,英文为1个字符)
  20. CoverageMaster winAMS

热门文章

  1. 怎样快速调整EDIUS 8中图片可见度
  2. 对工口游戏的看法(超雷人)
  3. Pytorch基础-07-自动编码器
  4. 三菱plc与计算机无协议通讯,三菱FX系列PLC与计算机无协议通讯.doc
  5. 如何使用 JSX 构建 Gutenberg 块
  6. 电子制造业生产进度监控困难?全流程条码管理轻松解决
  7. DB2和 Oracle的并发控制(锁)比较
  8. 《姜子牙》成营销流氓,国漫还能靠情怀买单吗?
  9. RTK与网络RTK技术的工作原理和区别对比
  10. Activiti7工作流引擎:基础篇(六) 任务监听器和流程监听器