文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

React性能优化总结

2024-12-14 01:13

关注

前言

目的

目前在工作中,大量的项目都是使用react来进行开展的,了解掌握下react的性能优化对项目的体验和可维护性都有很大的好处,下面介绍下在react中可以运用的一些性能优化方式;

性能优化思路

对于类式组件和函数式组件来看,都可以从以下几个方面去思考如何能够进行性能优化

减少重新render的次数

在react里时间耗时最多的一个地方是reconciliation(reconciliation 的最终目标是以最有效的方式,根据新的状态来更新 UI,我们可以简单地理解为 diff),如果不执行render,也就不需要reconciliation,所以可以看出减少render在性能优化过程中的重要程度了。

PureComponent

React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实现 shouldComponentUpdate(),而 React.PureComponent 中以浅层对比 prop 和 state 的方式来实现了该函数。

需要注意的是在使用PureComponent的组件中,在props或者state的属性值是对象的情况下,并不能阻止不必要的渲染,是因为自动加载的shouldComponentUpdate里面做的只是浅比较,所以想要用PureComponent的特性,应该遵守原则:

ShouldComponentUpdate

可以利用此事件来决定何时需要重新渲染组件。如果组件 props 更改或调用 setState,则此函数返回一个 Boolean 值,为true则会重新渲染组件,反之则不会重新渲染组件。

在这两种情况下组件都会重新渲染。我们可以在这个生命周期事件中放置一个自定义逻辑,以决定是否调用组件的 render 函数。

下面举一个小的例子来辅助理解下:

比如要在你的应用中展示学生的详细资料,每个学生都包含有多个属性,如姓名、年龄、爱好、身高、体重、家庭住址、父母姓名等;在这个组件场景中,只需要展示学生的姓名、年龄、住址,其他的信息不需要在这里展示,所以在理想情况下,除去姓名、年龄、住址以外的信息变化组件是不需要重新渲染的;

示例代码如下:

  1. import React from "react"
  2.  
  3. export default class ShouldComponentUpdateUsage extends React.Component { 
  4.  
  5.   constructor(props) { 
  6.     super(props); 
  7.     this.state = { 
  8.       name: "小明"
  9.       age: 12
  10.       address: "xxxxxx"
  11.       height: 165
  12.       weight: 40 
  13.     } 
  14.   } 
  15.  
  16.   componentDidMount() { 
  17.     setTimeout(() => { 
  18.       this.setState({ 
  19.         height: 168
  20.         weight: 45 
  21.       }); 
  22.     }, 5000
  23.   } 
  24.  
  25.   shouldComponentUpdate(nextProps, nextState) { 
  26.       if(nextState.name !== this.state.name || nextState.age !== this.state.age || nextState.address !== this.state.address) { 
  27.         return true
  28.       } 
  29.       return false
  30.   } 
  31.  
  32.   render() { 
  33.     const { name, age, address } = this.state; 
  34.     return ( 
  35.       
     
  36.         

    Student name: {name} 

     
  37.         

    Student age:{age} 

     
  38.         

    Student address:{address} 

     
  39.       
 
  •     ) 
  •   } 
  • 按照 React 团队的说法,shouldComponentUpdate是保证性能的紧急出口,既然是紧急出口,那就意味着我们轻易用不到它。但既然有这样一个紧急出口,那说明有时候它还是很有必要的。所以我们要搞清楚到底什么时候才需要使用这个紧急出口。

    使用原则

    当你觉得,被改变的state或者props,不需要更新视图时,你就应该思考要不要使用它。

    需要注意的一个地方是:改变之后,又不需要更新视图的状态,也不应该放在state中。

    shouldComponentUpdate的使用,也是有代价的。如果处理得不好,甚至比多render一次更消耗性能,另外也会使组件的复杂度增大,一般情况下使用PureComponent即可;

    React.memo

    如果你的组件在相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。

    React.memo 仅检查 props 变更 。如果函数组件被 React.memo 包裹,且其实现中拥有 useState,useReducer 或 useContext 的 Hook,当 state 或 context 发生变化时,它仍会重新渲染。

    默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

    1. function MyComponent(props) { 
    2.    
    3. function areEqual(prevProps, nextProps) { 
    4.    
    5. export default React.memo(MyComponent, areEqual); 

    注意

    与 class 组件中 shouldComponentUpdate() 方法不同的是,如果 props 相等,areEqual 会返回 true;如果 props 不相等,则返回 false。这与 shouldComponentUpdate 方法的返回值相反。

    合理使用Context

    Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。正是因为其这个特点,它是可以穿透React.memo或者shouldComponentUpdate的比对的,也就是说,一旦 Context 的 Value 变动,所有依赖该 Context 的组件会全部 forceUpdate.这个和 Mobx 和 Vue 的响应式系统不同,Context API 并不能细粒度地检测哪些组件依赖哪些状态。

    原则

    避免使用匿名函数

    首先来看下下面这段代码

    1. const MenuContainer = ({ list }) => ( 
    2.    
    3.     {list.map((i) => ( 
    4.        handleClick(i.id)} value={i.value} /> 
    5.     ))} 
    6.    
    7. ); 

    上面这个写法看起来是比较简洁,但是有一个潜在问题是匿名函数在每次渲染时都会有不同的引用,这样就会导致Menu组件会出现重复渲染的问题;可以使用useCallback来进行优化:

    1. const MenuContainer = ({ list }) => { 
    2.   const handleClick = useCallback( 
    3.     (id) => () => { 
    4.       // ... 
    5.     }, 
    6.     [], 
    7.   ); 
    8.  
    9.   return ( 
    10.      
    11.       {list.map((i) => ( 
    12.          
    13.       ))} 
    14.      
    15.   ); 
    16. }; 

    减少渲染的节点

    组件懒加载

    组件懒加载可以让react应用在真正需要展示这个组件的时候再去展示,可以比较有效的减少渲染的节点数提高页面的加载速度

    React官方在16.6版本后引入了新的特性:React.lazy 和 React.Suspense,这两个组件的配合使用可以比较方便进行组件懒加载的实现;

    React.lazy

    该方法主要的作用就是可以定义一个动态加载的组件,这可以直接缩减打包后bundle的体积,并且可以延迟加载在初次渲染时不需要渲染的组件,代码示例如下:

    使用之前

    1. import SomeComponent from './SomeComponent'

    使用之后

    1. const SomeComponent = React.lazy(() => import('./SomeComponent')); 

    使用 React.lazy 的动态引入特性需要 JS 环境支持 Promise。在 IE11 及以下版本的浏览器中需要通过引入 polyfill 来使用该特性。

    React.Suspense

    该组件目前主要的作用就是配合渲染lazy组件,这样就可以在等待加载lazy组件时展示loading元素,不至于直接空白,提升用户体验;

    Suspense组件中的 fallback 属性接受任何在组件加载过程中你想展示的 React 元素。你可以将 Suspense 组件置于懒加载组件之上的任何位置,你甚至可以用一个 Suspense 组件包裹多个懒加载组件。

    代码示例如下:

    1. import React, { Suspense } from 'react'
    2.  
    3. const OtherComponent = React.lazy(() => import('./OtherComponent')); 
    4. const AnotherComponent = React.lazy(() => import('./AnotherComponent')); 
    5.  
    6. function MyComponent() { 
    7.   return ( 
    8.     
       
    9.       Loading...
    }> 
  •         
     
  •            
  •            
  •          
  •        
  •      
  •   ); 
  • 有一点要特别注意的是:React.lazy 和 Suspense 技术还不支持服务端渲染。如果你想要在使用服务端渲染的应用中使用,推荐使用 Loadable Components 这个库,可以结合这个文档 服务端渲染打包指南 来进行查看。

    另外在业内也有一些比较成熟的react组件懒加载开源库: react-loadable 和 react-lazyload ,感兴趣的可以结合看下;

    虚拟列表

    虚拟列表是一种根据滚动容器元素的可视区域来渲染长列表数据中某一个部分数据的技术,在开发一些项目中,会遇到一些不是直接分页来加载列表数据的场景,在这种情况下可以考虑结合虚拟列表来进行优化,可以达到根据容器元素的高度以及列表项元素的高度来显示长列表数据中的某一个部分,而不是去完整地渲染长列表,以提高无限滚动的性能。

    可以关注下放两个比较常用的类库来进行深入了解

    降低渲染计算量

    useMemo

    先来看下useMemo的基本使用方法:

    1. function computeExpensiveValue(a, b) { 
    2.   // 计算量很大的一些逻辑 
    3.   return xxx 
    4.  
    5. const memoizedValue = useMemo(computeExpensiveValue, [a, b]); 

    useMemo 的第一个参数就是一个函数,这个函数返回的值会被缓存起来,同时这个值会作为 useMemo 的返回值,第二个参数是一个数组依赖,如果数组里面的值有变化,那么就会重新去执行第一个参数里面的函数,并将函数返回的值缓存起来并作为 useMemo 的返回值 。

    注意

    遍历展示视图时使用key

    key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。

    1. const numbers = [12345]; 
    2. const listItems = numbers.map((number) => 
    3.    
    4.     {number} 
    5.   
    6.  
    7. ); 

    使用key注意事项:

    合理设计组件

    简化props

    如果一个组件的props比较复杂的话,会影响shallowCompare的效率,也会使这个组件变得难以维护,另外也与“单一职责”的原则不符合,可以考虑进行拆解。

    简化State

    在设计组件的state时,可以按照这个原则来:需要组件响应它的变动或者需要渲染到视图中的数据,才放到 state 中;这样可以避免不必要的数据变动导致组件重新渲染。

    来源:lsqy'blog内容投诉

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    软考中级精品资料免费领

    • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

      难度     813人已做
      查看
    • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

      难度     354人已做
      查看
    • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

      难度     318人已做
      查看
    • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

      难度     435人已做
      查看
    • 2024年上半年系统架构设计师考试综合知识真题

      难度     224人已做
      查看

    相关文章

    发现更多好内容

    猜你喜欢

    AI推送时光机
    位置:首页-资讯-后端开发
    咦!没有更多了?去看看其它编程学习网 内容吧
    首页课程
    资料下载
    问答资讯