优化思路

主要优化的方向有2个:

  1. 减少重新 render 的次数。因为在 React 里最重(花时间最长)的一块就是 reconction(简单的可以理解为 diff),如果不 render,就不会 reconction。
  2. 减少计算的量。主要是减少重复计算,对于函数式组件来说,每次 render 都会重新从头开始执行函数调用。

在使用类组件的时候,使用的 React 优化 API 主要是:shouldComponentUpdate和 PureComponent

那么在函数式组件中,我们怎么做性能优化?主要用到下面几个方法去优化

  1. React.memo
  2. useCallback
  3. useMemo

React.memo

看个例子:

我们在父组件中放一个按钮用于修改子标题,并引入Child子组件

可以看到,第一次进来子组件打印了console.log('我是子组件')

当点击修改子标题,Child子组件也打印了,造成了不必要的重复渲染次数

//父组件
import {useState} from 'react' import Child from "./Child";
const Index = ()=>{
const [subTitle, setSubTitle] = useState('我是子标题')
const updateSubTitle = ()=>{
setSubTitle('修改子标题')
}
return (
<div>
<div>函数式组件性能优化</div>
<div>{subTitle}</div>
<button onClick={updateSubTitle}>修改子标题</button>
<Child/>
</div>
);
} export default Index; //子组件Child.js
const Child = ()=>{
console.log('我是子组件')
return (
<div>我是子组件</div>
)
}
export default Child

优化一下,使用React.memo包裹子组件

import React from "react";

const Child = ()=>{
console.log('我是子组件')
return (
<div>我是子组件</div>
)
}
export default React.memo(Child)

再观察一下,发现Child子组件没有重复渲染了

useCallback

这里我们再改造一下,给Child子组件添加一个onclick事件,然后点击修改子标题按钮,发现我们的Child子组件又重新渲染了,这里主要是因为修改子标题的时候handlerClick函数重新渲染变化,造成子组件重新渲染

// 父组件
const Index = ()=>{
const [subTitle, setSubTitle] = useState('我是子标题')
const updateSubTitle = ()=>{
setSubTitle('修改子标题')
}
const handlerClick = ()=>{
console.log('子组件点击')
}
return (
<div>
<div>函数式组件性能优化</div>
<div>{subTitle}</div>
<button onClick={updateSubTitle}>修改子标题</button>
<Child onClick={handlerClick}/>
</div>
);
} // Child子组件
const Child = (props)=>{
console.log('我是子组件')
return (
<div>
<div>我是子组件</div>
<button onClick={props.onClick}>子组件按钮</button>
</div>
)
}
export default React.memo(Child)

优化一下,使用useCallback包裹处理子组件的handlerClick函数,再次点击updateSubTitle修改子标题,发现Child子组件没有重新再渲染

// 父组件
const Index = ()=>{
const [subTitle, setSubTitle] = useState('我是子标题')
const updateSubTitle = ()=>{
setSubTitle('修改子标题')
}
const handlerClick = useCallback(()=>{
console.log('子组件点击')
},[]) return (
<div>
<div>函数式组件性能优化</div>
<div>{subTitle}</div>
<button onClick={updateSubTitle}>修改子标题</button>
<Child onClick={handlerClick}/>
</div>
);
} export default Index;

这里关于useCallback的用法

const callback = () => {
doSomething(a, b);
} const memoizedCallback = useCallback(callback, [a, b])

把函数以及依赖项作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,这个 memoizedCallback 只有在依赖项有变化的时候才会更新。

useMemo

useMemo用于计算结果缓存

我们先看个例子,在之前基础上添加一个calcCount计算函数,然后点击updateSubTitle更新子标题,发现calcCount重新计算了,也就是每次渲染都会造成重复计算,如果是计算量比较大的情况下,会极大的影响性能

// 父组件
const Index = ()=>{
const [subTitle, setSubTitle] = useState('我是子标题')
const updateSubTitle = ()=>{
setSubTitle('修改子标题')
}
const handlerClick = useCallback(()=>{
console.log('子组件点击')
},[]) const calcCount = ()=>{ let totalCount = 0
for(let i=0;i<10000;i++){
totalCount+=i
}
console.log('totalCount',totalCount)
return totalCount
} const count = calcCount() return (
<div>
<div>函数式组件性能优化</div>
<div>{subTitle}</div>
<button onClick={updateSubTitle}>修改子标题</button>
<div>count:{count}</div>
<Child onClick={handlerClick}/>
</div>
);
}

优化一下,使用useMemo缓存计算结果,我们再次点击updateSubTitle修改子标题按钮,可以发现calcCount函数不再重复计算

  const calcCount = ()=>{

      let totalCount = 0
for(let i=0;i<10000;i++){
totalCount+=i
}
console.log('totalCount',totalCount)
return totalCount
} const count = useMemo(calcCount,[])

最后,需要注意的是不能盲目的使用useMemo,要根据具体的场景,比如对于一个数据计算量比较大,那么使用是比较适用的,而对于普通的一些值得计算,可以不使用,因为本身useMemo也是会消耗一些性能,盲目使用反而会适得其反

参考阅读

文章最后

本文作者阿健Kerry,高级前端工程师,转载请注明出处。如果觉得本文对你有帮助,记得点赞三连哦,也可以扫码关注我新建立的前端技术公众号【有你前端】,之后我所有文章会同步发到这个公众号上面。另外,我建了一个可以帮助咱们程序员脱单的公众号,每周都会推送几个优秀的单身小姐姐,如果你是程序员技术好又正好是单身,那你可以下面扫码关注【缘来你是程序猿】公众号开启你的脱单之旅。

React函数式组件的性能优化的更多相关文章

  1. 如何对 React 函数式组件进行优化

    文章首发个人博客 前言 目的 本文只介绍函数式组件特有的性能优化方式,类组件和函数式组件都有的不介绍,比如 key 的使用.另外本文不详细的介绍 API 的使用,后面也许会写,其实想用好 hooks ...

  2. react第八单元(什么是纯函数-组件的性能优化-pureComponent-组件性能优化的原理)

    课程目标 理解纯函数 熟练掌握组件性能优化的几种技巧 pureComponent和Component的区别 #知识点 一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数 ...

  3. React 16 加载性能优化指南

    关于 React 应用加载的优化,其实网上类似的文章已经有太多太多了,随便一搜就是一堆,已经成为了一个老生常谈的问题. 但随着 React 16 和 Webpack 4.0 的发布,很多过去的优化手段 ...

  4. 【React】393 深入了解React 渲染原理及性能优化

    如今的前端,框架横行,出去面试问到框架是常有的事. 我比较常用React, 这里就写了一篇 React 基础原理的内容, 面试基本上也就问这些, 分享给大家. React 是什么 React是一个专注 ...

  5. React函数式组件使用Ref

    目录: 简介 useRef forwardRef useImperativeHandle 回调Ref 简介 大家都知道React中的ref属性可以帮助我们获取子组件的实例或者Dom对象,进而对子组件进 ...

  6. React 函数式组件的 Ref 和子组件访问(useImperativeHandle)

    引入:如何调用函数式组件内部的方法 对于 React 中需要强制修改子组件的情况,React 提供了 Refs 这种解决办法,使得我们可以操作底层 DOM 元素或者自定的 class 组件实例.除此之 ...

  7. React函数式组件和类组件[Dan]

    一篇对Dan的 How Are Function Components Different from Classes? 一文的个人阅读总结,内容来自于此.强烈推荐阅读 Dan Abramov.的博客. ...

  8. react教程 — 性能优化

    参考:https://segmentfault.com/a/1190000007811296?utm_medium=referral&utm_source=tuicool  或  https: ...

  9. React性能优化,六个小技巧教你减少组件无效渲染

    壹 ❀ 引 在过去的一段时间,我一直围绕项目中体验不好或者无效渲染较为严重的组件做性能优化,多少积累了一些经验所以想着整理成一片文章,下图就是优化后的一个组件,可以对比优化前一次切换与优化后多次切换的 ...

随机推荐

  1. 从微信小程序到鸿蒙js开发【15】——JS调用Java

    鸿蒙入门指南,小白速来!0基础学习路线分享,高效学习方法,重点答疑解惑--->[课程入口] 目录:1.新建一个Service Ability2.完善代码逻辑3.JS端远程调用4.<从微信小 ...

  2. mysql索引的性能分析

    [前言]上一篇博客介绍了InnoDB引擎的索引机制,主要围绕B+树的建立,目录项记录里主键和页号,到页目录下的二分法定位数据:二级索引里的主键和索引列,及其回表操作.这一篇分析一下索引的性能,围绕如何 ...

  3. RabbitMQ(三) SpringBoot2.x 集成 RabbitMQ

    3-1 RabbitMQ 整合 SpringBoot2.x 生产者发送消息 创建 SpringBoot 项目application.properties 配置 spring.rabbitmq.host ...

  4. 后端程序员之路 40、Pthreads

    POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准.线程这个东西在操作系统原理里讲得比较清楚了,再加上对windows那一套进程线程的东西比较清楚,所以这里还是 ...

  5. Codeforces Global Round 13

    比赛地址 A(水题) 题目链接 题目: 给出一个\(01\)序列,有2种操作:1.将某个位置取反:2.询问\(01\)序列中第\(k\)大的数 解析: 显然维护1的数目即可 #include<b ...

  6. 49元起!魅族Lipro LED灯泡发布:无可视频闪、无积热问题

    转: 49元起!魅族Lipro LED灯泡发布:无可视频闪.无积热问题 魅族智能家居品牌Lipro今日办会,公布一批新品,均面向健康照明领域打造. 魅族强调,Lipro健康照明产品主打博物馆级健康光. ...

  7. 【Azure 云服务】Azure Cloud Service在发布新部署后遇见不能RDP(远程连接)到实例时如何处理?

    Azure 云服务是PaaS 的一个示例. 与 Azure 应用服务一样,此技术设计用于支持可缩放.可靠且运营成本低廉的应用程序. 同样,应用服务托管在虚拟机 (VM) 上,Azure 云服务也是如此 ...

  8. React函数式组件和类组件[Dan]

    一篇对Dan的 How Are Function Components Different from Classes? 一文的个人阅读总结,内容来自于此.强烈推荐阅读 Dan Abramov.的博客. ...

  9. const修饰符相关

    const修饰符相关 const修饰符表明一个变量是常量,大致分为三类:常量数组(等同于常量指针),常量指针,指向常量的指针. 常量数组中数据都是不可修改的,任何试图修改常量数组中的数据的操作都会报错 ...

  10. C#的常见集合接口提供的功能

    C#的常见集合接口提供的功能 这里的功能都是泛型版本的常见功能,列出来,也许后面用得上吧,没有放非泛型版本,因为觉得用得不多,也就没有整理 IEnumerable<T> ICollecti ...