当前位置:首页 > 技术分析 > 正文内容

面试官:说说 React 性能优化的手段有哪些?

ruisui884个月前 (02-03)技术分析23

作者:灰灰 来源:JS每日一题

一、是什么

React凭借virtual DOM和diff算法拥有高效的性能,但是某些情况下,性能明显可以进一步提高

在前面文章中,我们了解到类组件通过调用setState方法, 就会导致render,父组件一旦发生render渲染,子组件一定也会执行render渲染

当我们想要更新一个子组件的时候,如下图绿色部分:

理想状态只调用该路径下的组件render:

但是react的默认做法是调用所有组件的render,再对生成的虚拟DOM进行对比(黄色部分),如不变则不进行更新

从上图可见,黄色部分diff算法对比是明显的性能浪费的情况

二、如何做

在React中如何避免不必要的render中,我们了解到如何避免不必要的render来应付上面的问题,主要手段是通过shouldComponentUpdate、PureComponent、React.memo,这三种形式这里就不再复述

除此之外, 常见性能优化常见的手段有如下:

  • 避免使用内联函数
  • 使用 React Fragments 避免额外标记
  • 使用 Immutable
  • 懒加载组件
  • 事件绑定方式
  • 服务端渲染

避免使用内联函数

如果我们使用内联函数,则每次调用render函数时都会创建一个新的函数实例,如下:

import React from "react";
export default class InlineFunctionComponent extends React.Component {
  render() {
    return (
      <div>
                <h1>Welcome Guest</h1>
               <input type="button" onClick={(e) => { this.setState({inputValue: e.target.value}) }} value="Click For Inline Function" />
  </div>
  )
}
} 

我们应该在组件内部创建一个函数,并将事件绑定到该函数本身。这样每次调用 render 时就不会创建单独的函数实例,如下:

import React from "react";  export default class InlineFunctionComponent extends React.Component {      setNewStateData = (event) => {     this.setState({       inputValue: e.target.value     })   }      render() {     return (       <div>         <h1>Welcome Guest</h1>         <input type="button" onClick={this.setNewStateData} value="Click For Inline Function" />       </div>     )   } } 

使用 React Fragments 避免额外标记

用户创建新组件时,每个组件应具有单个父标签。父级不能有两个标签,所以顶部要有一个公共标签,所以我们经常在组件顶部添加额外标签div

这个额外标签除了充当父标签之外,并没有其他作用,这时候则可以使用fragement

其不会向组件引入任何额外标记,但它可以作为父级标签的作用,如下所示:

export default class NestedRoutingComponent extends React.Component {
  render() {
    return (
      <> 
      <h1>This is the Header Component</h1>
      <h2>Welcome To Demo Page</h2>
      </> 
    ) 
  }
} 

事件绑定方式

在事件绑定方式中,我们了解到四种事件绑定的方式

从性能方面考虑,在render方法中使用bind和render方法中使用箭头函数这两种形式在每次组件render的时候都会生成新的方法实例,性能欠缺

而constructor中bind事件与定义阶段使用箭头函数绑定这两种形式只会生成一个方法实例,性能方面会有所改善

使用 Immutable

在理解Immutable中,我们了解到使用 Immutable可以给 React 应用带来性能的优化,主要体现在减少渲染的次数

在做react性能优化的时候,为了避免重复渲染,我们会在shouldComponentUpdate()中做对比,当返回true执行render方法

Immutable通过is方法则可以完成对比,而无需像一样通过深度比较的方式比较

懒加载组件

从工程方面考虑,webpack存在代码拆分能力,可以为应用创建多个包,并在运行时动态加载,减少初始包的大小

而在react中使用到了Suspense和 lazy组件实现代码拆分功能,基本使用如下:

const johanComponent = React.lazy(() => import(/* webpackChunkName: "johanComponent" */ './myAwesome.component'));
export const johanAsyncComponent = props => ( 
  <React.Suspense fallback={<Spinner />}>
  <johanComponent {...props} />
</React.Suspense> 
); 

服务端渲染

采用服务端渲染端方式,可以使用户更快的看到渲染完成的页面

服务端渲染,需要起一个node服务,可以使用express、koa等,调用react的renderToString方法,将根组件渲染成字符串,再输出到响应中

例如:

import { renderToString } from "react-dom/server"; 
import MyPage from "./MyPage"; 
app.get("/", (req, res) => { 
  res.write("
            <!DOCTYPE html>
            <html>
            <head>
            <title>My Page</title>
            </head>
            <body>"
           );  
  res.write("<div id='content'>");    
  res.write(renderToString(<MyPage/>));   
  res.write("</div></body></html>");   
  res.end();
}); 

客户端使用render方法来生成HTML

import ReactDOM from 'react-dom'; 
import MyPage from "./MyPage";
ReactDOM.render(<MyPage />, document.getElementById('app')); 

其他

除此之外,还存在的优化手段有组件拆分、合理使用hooks等性能优化手段...

三、总结

通过上面初步学习,我们了解到react常见的性能优化可以分成三个层面:

  • 代码层面
  • 工程层面
  • 框架机制层面

通过这三个层面的优化结合,能够使基于react项目的性能更上一层楼

参考文献

https://zhuanlan.zhihu.com/p/108666350

https://segmentfault.com/a/1190000007811296

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/1139.html

标签: nodejs更新
分享给朋友:

“面试官:说说 React 性能优化的手段有哪些?” 的相关文章

几个linux发行版使用感受

linux发行版有哪些linux发行版有上千种,但每一种发行版并不是与其它的发行版没任何关系,有些发行版是基于其他发行版制作的。如果乐意,你自己也可以动手制作属于自己的发行版,然后分发给其他人使用,所以非常自由,可选择的非常多。常见的发行版有:RedHat、Ubuntu、OpenSUSE、Gento...

Linux Lite 6.6发行版正式发布:添加简体中文及AI工具支持

IT之家 9 月 8 日消息,Linux Lite 是一个对新手友好的 Linux 发行版,它基于 Ubuntu LTS,并以 Xfce 桌面为特色,主要针对 Windows 用户而设计,也被认为是从 Windows 过渡到 Linux 的友好方案。目前 Linux Lite 6.6 版本已经正式发...

最古老的Linux发行版刚刚进行了重大更新

Slackware 15.0 带来了全新的 KDE Plasma 5 桌面体验。Slackware Linux(仍然维护的最古老的Linux发行版)的制造商刚刚发布了Linux发行版的15.0版本。Slackware Linux于1993年出现,创始人Patrick Volderding今天继续维护...

vue父组件修改子组件的值(通过调用子组件的方法)

props只支持第一次加载这个组件的时候获取父组件的值,后续修改父组件的值得时候子组件并不会动态的更改。然而我们想要通过父组件修改子组件的值要怎么做呢?可以通过ref的方式调用子组件的方法改变子组件的值。子组件<template><div><span>{{data...

千智云低代码平台 v2.0.6发布「平台升级」

【平台简介】千智云低代码应用平台是一款低代码开发+低代码PaaS+SaaS应用中台为一体的应用平台。平台提供了多种应用场景功能及应用组件,满足各种应用的基本实现,可以使用低代码开发的方式,定制化的开发软件项目,并使用平台提供的各种功能,提供了大多数业务场景的支持。也可以将开发的应用发布到平台,成为S...

微信研发新功能,或许有你最期待的

微信在我们日常社交中担任着非常重要的角色,不管是用于学习还是工作,我们越来越离不开微信,微信的任何一个小的变化都会影响到现如今超过12亿的微信用户。就在前一段时间,微信更新了一个“拍一拍”的功能,只要双击好友头像,头像就会有抖动并带有文字提示,一时间众多网友在朋友圈疯狂刷屏,虽然觉得这个功能毫无用处...