【React】react 性能优化的方式有哪些

2023-11-04


react凭借 virtual DOMdiff算法拥有高效的性能,除此之外也有很多其他的方法和技巧可以进一步提升react性能。一下几中方法有助于提升react性能,虽然不必一定要在项目中使用这些方法,但是我们有应该知道如何使用这些方法。

1 Reac.memo 缓存组件

提示应用程序性能的一种方法是实现 memoization。Memoization 是一种优化技术,主要通过昂贵的函数调用结果,并在再次发生相同的输入时返回缓存的结果,以此来加速程序。

React 中父组件每次更新都会导致子组件重新渲染,即使子组件的状态没有发生变化。

为了减少重复渲染,我们可以使用 React.memo来缓存组件,这样只有在传入组件的状态值发生变化时才会从新渲染。如果传入的值相同,则会返回缓存的组件。

示例:

// 使用 React.memo 将子组件包括起来
const Child = React.memo((props) => {
    console.log('子组件');
    return <div>子组件</div>
}
)

const App = () => {
    console.log('父组件');
    const [count, setCount] = useState(0);
    return(<>
    	<div>父组件:count:{count}</div>
        <button onClick={() => setCount(count + 1)}>点击更新</button>
        <Child />
    </>)
}

2 使用 useMemo 缓存大量的计算

有时渲染是不可避免的,但如果您的组件是一个功能组件,重新渲染会导致每次都调用大型计算函数,这是非常消耗性能的,我们可以使用新的useMemo钩子来“记忆”这个计算函数的计算结果。这样只有传入的参数发生变化后,该计算函数才会重新调用计算新的结果。

通过这种方式,您可以使用从先前渲染计算的结果来挽救昂贵的计算耗时。总体目标是减少JavaScript在呈现组件期间必须执行的工作量,以便主线程被阻塞的时间更短。

// 避免这样做,每次传值都会调用 countFn 计算函数
function Component(props) {
  const res = countFn(props.item);
  return <div>{res}</div>
}
  
// 只有 props.item 改变时 res 的值才会被重新计算
function Component(props) {
  const res = useMemo(() => countFn(props.item), [props.item]);
  return <div>{res}</div>
}
  
// 计算函数
const countFn = (item) => {
    ...
}

3 避免使用 内联对象

使用内联对象时,react会在每次渲染时重新创建对此对象的引用,这会导致接收此对象的组件将其视为不同的对象。因此,该组件对于props的千层比较始终返回false,导致组件一直渲染。

// Don't do this!
function Component(props) {
  const aProp = { someProp: 'someValue' }
  return <AComponent style={{ margin: 0 }} aProp={aProp} />  
}

// Do this instead :)
const styles = { margin: 0 };
function Component(props) {
  const aProp = { someProp: 'someValue' }
  return <AComponent style={styles} {...aProp} />  
}

4 避免使用 匿名函数

虽然匿名函数是传递函数的好方法,但它们在每次渲染上都有不同的引用。类似于内联对象。

为了保证作为props传递给react组件的函数的相同引用,如果使用的类组件可以将其声明为类方法,如果使用的函数组件,可以使用useCallback钩子来保持相同的引用。

// 避免这样做
function Component(props) {
  return <AComponent onChange={() => props.callback(props.id)} />  
}

// 函数组件,优化方法一
function Component(props) {
  const handleChange = useCallback(() => props.callback(props.id), [props.id]);
  return <AComponent onChange={handleChange} />  
}

// 类组件,优化方法二
class Component extends React.Component {
  handleChange = () => {
   this.props.callback(this.props.id) 
  }
  render() {
    return <AComponent onChange={this.handleChange} />
  }
}

5 延迟加载不是立即需要的组件

使用React.lazyReact.Suspense完成延迟加载不是立即需要的组件。React加载的组件越少,加载组件的速度越快。

// React.lazy 接受一个函数,这个函数需要动态调用 import()引入组件
const HomeIndex = React.lazy(() => import('@/modules/home'))
......

// 然后应在 Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)
return(
    <React.Suspense fallback={<>Loading...</>}>
        <HomeIndex />
    </React.Suspense>
)


// 一般会封装一个公共的方法
const withLoadingComponent = (comp: JSX.Element) => (
  <React.Suspense fallback={<>Loading...</>}>
    {comp}
  </React.Suspense>
)

// 调用方法,传入要延迟加载的组件
return(
	{withLoadingComponent(<HomeIndex />}
)

6 调整CSS而不是强制组件加载和卸载

有时保持组件加载的同时,通过CSS隐藏可能是有益的,而不是通过卸载来隐藏。对于具有显著的加载或卸载时序的重型组件而言,这是有效的性能优化手段。

将元素透明度调整为0对浏览器的成本消耗几乎为0(因为它不会导致重排),并且应该尽可能优先更改visibility或display。

// 避免对大型的组件频繁对加载和卸载
function Component(props) {
  const [view, setView] = useState('view1');
  return view === 'view1' ? <AComponent /> : <BComponent />  
}

// 使用该方式提升性能和速度
const visibleStyles = { opacity: 1 };
const hiddenStyles = { opacity: 0 };
function Component(props) {
  const [view, setView] = useState('view1');
  return (
    <React.Fragment>
      <AComponent style={view === 'view1' ? visibleStyles : hiddenStyles}>
      <BComponent style={view !== 'view1' ? hiddenStyles : visibleStyles}>
    </React.Fragment>
  )
}

7 使用React.Fragment避免添加额外的DOM

有些情况下,我们需要在组件中返回多个元素,例如下面的元素,但是在react规定组件中必须有一个父元素。

	<h1>Hello world!</h1>
	<h1>Hello there!</h1>
	<h1>Hello there again!</h1>

因此可能会这样做,但是这样做的话即使一切正常,也会创建额外的不必要的div。这会导致整个应用程序内创建许多无用的元素:

function Component() {
        return (
            <div>
                <h1>Hello world!</h1>
                <h1>Hello there!</h1>
                <h1>Hello there again!</h1>
            </div>
        )
}

实际上页面上的元素越多,加载所需的时间就越多。为了减少不必要的加载时间,我们可以使React.Fragment来避免创建不必要的元素。

function Component() {
        return (
            <React.Fragment>
                <h1>Hello world!</h1>
                <h1>Hello there!</h1>
                <h1>Hello there again!</h1>
            </React.Fragment>
        )
}

8 使用React.PureComponent , shouldComponentUpdate

父组件状态的每次更新,都会导致子组件的重新渲染,即使是传入相同props。但是这里的重新渲染不是说会更新DOM,而是每次都会调用diif算法来判断是否需要更新DOM。这对于大型组件例如组件树来说是非常消耗性能的。
在这里我们就可以使用React.PureComponent , shouldComponentUpdate生命周期来确保只有当组件props状态改变时才会重新渲染。如下例子:

export default function ParentComponent(props) {
  return (
    <div>
      <SomeComponent someProp={props.somePropValue}
    <div>
      <AnotherComponent someOtherProp={props.someOtherPropValue} />
    </div>
   </div>
 )
}

export default function SomeComponent(props) {
  return (
    <div>{props.someProp}</div>  
  )
}

// 只要props.somePropValue 发生变化,不论props.someOtherPropValue是否发生变化该组件都会发生变化
export default function AnotherComponent(props) {
  return (
    <div>{props.someOtherProp}</div>  
  )
}

转载

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【React】react 性能优化的方式有哪些 的相关文章

随机推荐

  • 页面加载与iframe加载函数

  • 运算放大器基础知识

    文章目录 前言 一 运放内部电路原理 二 运放的参数和特性 1 输入输出特性曲线 2 主要参数 三 运放常用应用 1 加法器 2 减法器 3 读书电路和指数电路 4 乘法器和除法器 5 乘方和开平方根电路 6 积分电路 7 微分电路 8 P
  • Spring-Boot添加MyBatis:手动添加代码方式

    创建了一个MySQL数据库 并添加了一张表 添加MyBatis后 有两种使用方式 注解方式 简单快速 适合规模较小的数据库 xml配置方式 支持动态生成SQL 调整SQL更方便 适合大型数据库 无论哪种方式 都需要共同执行的前期工作 在po
  • Raspberry Pi运行Arduino Sketch

    在本文中 您将学习如何在Raspberry Pi上运行为Arduino编写的sketch 这将使我们能够将Arduino代码编译为可以在Raspberry Pi上运行的二进制文件 但是在我们这样做之前 我们必须在Arduino IDE和Ra
  • 剑指Offer第五十九题:按之字顺序打印二叉树

    题目描述 请实现一个函数按照之字形打印二叉树 即第一行按照从左到右的顺序打印 第二层按照从右至左的顺序打印 第三行按照从左到右的顺序打印 其他行以此类推 思路 1 第一种按照层序遍历 然后偶数行 默认从第一行开始 翻转即可 层序遍历和翻转可
  • iOS并发编程(一)-简介

    一个菜鸟的自我修养 就是在低级职位上不抓狂 当一个优秀的菜鸟 就是为了有一天不当菜鸟 瞅准机会迅速脱离菜鸟轨道 然后一路飞翔到世界的尽头 接下来系统的学习下并发编程 会有几篇吧 不多说 走起 简介 1 异步设计方式 传统并发编程模型是线程
  • 三分钟看懂Python分支循环规范:if elif for while

    人生苦短 我用python 分支与循环 条件是分支与循环中最为核心的点 解决的问题场景是不同的问题有不同的处理逻辑 当满足单个或者多个条件或者不满足条件进入分支和循环 这里也就说明这个对相同问题处理执行逻辑依据具体参数动态变化 由此产生多种
  • linux环境安装工具

    安装mysql http istester com article 258 html 安装git https wx zsxq com dweb2 index group 88512425825412 from mweb type detai
  • java批量生成二维码图片,并打包成ZIP

    最近开发遇到了一个批量打印二维码并生成zip包的需求 先记录下来 pom依赖
  • MySQL(免安装版)的安装与配置详细教程及相关问题解决办法、开启远程连接

    免安装版的Mysql MySQL关是一种关系数据库管理系统 所使用的 SQL 语言是用于访问数据库的最常用的标准化语言 其特点为体积小 速度快 总体拥有成本低 尤其是开放源码这一特点 在 Web应用方面 MySQL 是最好RDBMS Rel
  • 小程序设计规范(一)

    小程序设计规范 标签 相比APP而言 开发一款小程序的开发成本更低 周期更短 同时开发难度和维护成本也相对降低 因此越来越多的开发者开始入坑小程序 正好最近我也要开发小程序 所以今天我就从设计方面聊一聊微信小程序设计规范 埋上设计中可能会出
  • CTP:报单错误:不允许重复报单(原因及解决方案)

    CTP 报单错误 不允许重复报单 原因及解决方案 使用QT5 10 上期的CTP平台开发了一整套程序化交易系统 开发的过程中遇到了各种各样的问题 其中关于CTP接口的开发就遇到了很多坑 甚至很多坑是经过了一段时间的实盘测试才能被发现 本文所
  • python中斐波那契数列_斐波那契数列–在Python,JavaScript,C ++,Java和Swift中进行了解释...

    python中斐波那契数列 by Pau Pav n 通过保罗 帕文 PauPav n The Fibonacci sequence is by definition the integer sequence in which every
  • 学习梦想家CMS内容管理系统-模板的使用

    准备网站下载器 网上可以自己百度搜索 我使用的这个工具就是HTTrack Website Copier 通过这个工具完成一个网站的获取 主要是获取静态文件 这里需要自己去分析这个静态文件 我们获取到的页面主要是需要css images js
  • linux 命令:ping、fping、gping、hping3、tracert、traceroute

    From Nmap Netcat Hping3工具对比 http www 2cto com article 201210 158961 html hping3 命令 http man linuxde net hping3 示例 Testin
  • 2023年最热门的网络安全行业岗位分析

    前言 大数据 人工智能 云计算 物联网 5G等新兴技术的高速发展 蒸蒸日上 但是随之也出现了许多问题 比如 政府单位 企业 个人信息泄露 网络安全问题日益严峻 网络空间安全建设刻不容缓 网络安全人才需求量巨大 人才缺口高达95 人才输送与人
  • m = (++i)+(++i)+(++i) 问题

    m i i i 问题 问题描述 m i i i i初始值为1 求m计算结果 解析 计算机在计算m a b c d e f 先计算 a b c d 并把结果存储 例如 存储在j中 然后再计算j e f j 所以计算机先计算了两个 i 前两项i
  • SpringBoot+Netty实现WebSocket服务器

    前言 传统的请求 应答模式 http 越来越不能满足现实需求 服务器过于被动 而采用轮训或者long poll的方式过于浪费资源 这便有了WebSocket WebSocket是HTML5出的东西 协议 也就是说HTTP协议没有变化 或者说
  • 闲鱼x-sign参数

    据说淘宝的x sign程序已经人手一份了 闲鱼的好像不太多 最近研究了下闲鱼以x sign为代码的请求参数 包括x sign x mini wua x umt等等参数 效果如下 可以看到基本的请求参数和请求包数据都已经在里面了 上面的是po
  • 【React】react 性能优化的方式有哪些

    文章目录 1 Reac memo 缓存组件 2 使用 useMemo 缓存大量的计算 3 避免使用 内联对象 4 避免使用 匿名函数 5 延迟加载不是立即需要的组件 6 调整CSS而不是强制组件加载和卸载 7 使用React Fragmen