React函数式组件的性能优化思路详解

优化思路

主要优化的方向有2个:

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

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

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

  • React.memo
  • useCallback
  • 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也是会消耗一些性能,盲目使用反而会适得其反

参考阅读

https://mp.weixin.qq.com/s/YGvmSrr-yhPUNHbwlLSFsA

http://www.ptbird.cn/react-hook-useMemo-purerender.html

到此这篇关于React函数式组件的性能优化的文章就介绍到这了,更多相关React性能优化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • React性能优化系列之减少props改变的实现方法

    React性能优化的一个核心点就是减少render的次数.如果你的组件没有做过特殊的处理(SCU -- shouldComponentUpdate或使用PureComponent),那每次父组件render时,子组件就会跟着一起被重新渲染.通常一个复杂的子组件都会进行一些优化,比如:SCU 使用PureComponent组件.对于SCU基本上进行的也都是浅比较,深比较的代价太高. 对于这些被优化的子组件,我们要减少一些不必要的props改变:比如事件绑定.对于那些依赖于配置项的组件,我们更是减少

  • react性能优化达到最大化的方法 immutable.js使用的必要性

    一行代码胜过千言万语.这篇文章呢,主要讲述我一步一步优化react性能的过程,为什么要用immutable.js呢.毫不夸张的说.有了immutable.js(当然也有其他实现库)..才能将react的性能发挥到极致!要是各位看官用过一段时间的react,而没有用immutable那么本文非常适合你.那么我开始吧! 1.对于react的来说,如果父组件有多个子组件 想象一下这种场景,一个父组件下面一大堆子组件.然后呢,这个父组件re-render.是不是下面的子组件都得跟着re-render.可

  • 浅谈React组件之性能优化

    高德纳: "我们应该忘记忽略很小的性能优化,可以说97%的情况下,过早的优化是万恶之源,而我们应该关心对性能影响最关键的另外3%的代码." 不要将性能优化的精力浪费在对整体性能提高不大的代码上,而对性能有关键影响的部分,优化并不嫌早.因为,对性能影响最关键的部分,往往涉及解决方案核心,决定整体的架构,将来要改变的时候牵扯更大. 1. 单个React组件的性能优化 React利用Virtual DOM来提升渲染性能,虽然每一次页面更新都是最组件的从新渲染,但是并不是将之前的渲染内容全部抛

  • 浅谈react性能优化的方法

    React性能优化思路 软件的性能优化思路就像生活中去看病,大致是这样的: 使用工具来分析性能瓶颈(找病根) 尝试使用优化技巧解决这些问题(服药) 使用工具测试性能是否确实有提升(疗效确认) 初识react只是为了尽快完成项目,后期进行代码审查时候发现有很多地方需要优化,因此做了个小结. Code Splitting shouldComponentUpdate避免重复渲染 使用不可突变数据结构 组件尽可能的进行拆分.解耦 列表类组件优化 bind函数优化 不要滥用props ReactDOMSe

  • React函数式组件的性能优化思路详解

    优化思路 主要优化的方向有2个: 减少重新 render 的次数.因为在 React 里最重(花时间最长)的一块就是 reconction(简单的可以理解为 diff),如果不 render,就不会 reconction. 减少计算的量.主要是减少重复计算,对于函数式组件来说,每次 render 都会重新从头开始执行函数调用. 在使用类组件的时候,使用的 React 优化 API 主要是:shouldComponentUpdate和 PureComponent 那么在函数式组件中,我们怎么做性能

  • React 首页加载慢问题性能优化案例详解

    学习了一段时间React,想真实的实践一下.于是便把我的个人博客网站进行了重构.花了大概一周多时间,网站倒是重构的比较成功,但是一上线啊,那个访问速度啊,是真心慢,慢到自己都不能忍受,那么小一个网站,没几篇文章,慢成那样,不能接受.我不是一个追求完美的人,但这样可不行.后面大概花了一点时间进行性能的研究.才发现慢是有原因的. React这类框架? 目前主流的前端框架React.Vue.Angular都是采用客户端渲染(服务端渲染暂时不在本文的考虑范围内).这当然极大的减轻了服务器的压力.相对的浏

  • Oracle分页查询性能优化代码详解

    对于数据库中表的数据的 Web 显示,如果没有展示顺序的需要,而且因为满足条件的记录如此之多,就不得不对数据进行分页处理.常常用户并不是对所有数据都感兴趣的,或者大部分情况下,他们只看前几页. 通常有以下两种分页技术可供选择. Select * from ( Select rownum rn,t.* from table t) Where rn>&minnum and rn<=&maxnum 或者 Select * from ( Select rownum rn,t.* fro

  • 大规格文件的上传优化思路详解

    在开发过程中,收到这样一个问题反馈,在网站上传 100 MB 以上的文件经常失败,重试也要等老半天,这就难为需要上传大规格文件的用户了.那么应该怎么做才能快速上传,就算失败了再次发送也能从上次中断的地方继续上传呢?下文为你揭晓答案~ 温馨提示:配合 Demo 源码一起阅读效果更佳 整体思路 第一步是结合项目背景,调研比较优化的解决方案. 文件上传失败是老生常谈的问题,常用方案是将一个大文件切片成多个小文件,并行请求接口进行上传,所有请求得到响应后,在服务器端合并所有的分片文件.当分片上传失败,可

  • JavaScript 文件加载与阻塞问题之性能优化案例详解

    上来先给一个问题:在书写html页面时,当你要从外部引入js文件时,script标签会放置在哪个位置呢,放置位置不同对页面加载有影响吗? 默认情况下,浏览器是同步加载 JavaScript 脚本:即渲染引擎遇到 script 标签就会停下来,等到执行完脚本,再继续向下渲染.如果是外部脚本,还必须加入脚本下载的时间. 如果脚本体积很大,下载和执行的时间就会很长,因此造成浏览器堵塞,用户会感觉到浏览器"卡死",出现短暂的空白,没有任何响应.这会造成很不好的用户体验,解决这个问题有两种方案:

  • react通过组件拆分实现购物车界面详解

    目录 页面组件拆分图 功能点 页面组件拆分图 功能点 实现全选反选 数量的增加和减少 选中删除,单独删除 商品总价和商品总数量的变化 首先在根组件中把页面的布局以及功能先实现,然后再拆分组件,最后通过组件传值进行属性和方法的传递 代码展示 app.js组件 import axios from 'axios'; import React, { Component } from 'react'; import './App.css'; import Cartfoot from './Componen

  • 一次 Java 服务性能优化实例详解

    背景 前段时间我们的服务遇到了性能瓶颈,由于前期需求太急没有注意这方面的优化,到了要还技术债的时候就非常痛苦了. 在很低的 QPS 压力下服务器 load 就能达到 10-20,CPU 使用率 60% 以上,而且在每次流量峰值时接口都会大量报错,虽然使用了服务熔断框架 Hystrix,但熔断后服务却迟迟不能恢复.每次变更上线更是提心吊胆,担心会成为压死骆驼的最后一根稻草,导致服务雪崩. 在需求终于缓下来后,leader 给我们定下目标,限我们在两周内把服务性能问题彻底解决.近两周的排查和梳理中,

  • vue虚拟滚动性能优化方式详解

    目录 引言 虚拟滚动(Virtual Scrolling) 理解虚拟滚动 虚拟 滚动 实现虚拟滚动 核心步骤 效果预览 最后 引言 一个简单的情景模拟(千万别被带入): A: 假设现在有 10 万条数据,你作为前端该怎么优化这种大数据的列表? B: 针对大数据列表一般不会依次性加载,会采用上拉加载.分页加载等方式实现优化. A: 那假如加载到最后一条数据的时候,页面上只是列表部分的数据就至少对应 10 万个 dom 节点,你觉得一个页面渲染至少 10 万个 dom 节点的性能如何? A: 如果这

  • 基于python的Linux系统指定进程性能监控思路详解

    监控Linux服务器的工具.组件和程序网上有很多,但是一台服务器上会有很多进程同时运行,特别是做性能测试的时候,可能一台服务器上部署多个服务,如果只监控整个服务器的CPU和内存,当某个服务出现性能问题时,并不能有效准确的定位出(当然通过其他工具也可以实现),因此,很有必要只监控指定的进程.需求明确了,于是动手撸了一个性能监控脚本. 一.整体思路 1.为了方便的启动监控和停止监控,在想查看监控结果的时候随时查看监控结果,用flask开启了一个服务,通过发送get请求可以随时启停监控和查看监控结果.

  • React传值 组件传值 之间的关系详解

    react 组件相互之间的传值: 传值分父级组件传值给子组件 子组件传值给父组件 平级组件.没有嵌套的组件相互传值 1.父组件向子组件传值 父组件通过属性的形式来向子组件传值,子组件通过props来接受父组件传递过来的参数 //子组件 class list extends React.Component{ constructor(props){ super(props); // 初始化可以不用管 } render(){ return( <div> <div>{this.props.

随机推荐