React之如何进行性能优化

news/2024/7/15 17:01:32 标签: react.js, javascript, 前端

一、是什么

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

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

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

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

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

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

二、如何做

在React中如何避免不必要的render (opens new window)中,我们了解到如何避免不必要的render来应付上面的问题,主要手段是通过shouldComponentUpdatePureComponentReact.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>
            </>
        )
    }
}

事件绑定方式

在事件绑定方式 (opens new window)中,我们了解到四种事假绑定的方式

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

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

使用 Immutable

在理解Immutable中 (opens new window),我们了解到使用 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服务,可以使用expresskoa等,调用reactrenderToString方法,将根组件渲染成字符串,再输出到响应中

例如:

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项目的性能更上一层楼


http://www.niftyadmin.cn/n/5133790.html

相关文章

【java学习—十】HashSet集合(4)

文章目录 1. Java集合概述2. HashSet3. 泛型 1. Java集合概述 Java 集合类存放于 java.util 包中&#xff0c;是一个用来存放对象的容器。 ① 集合只能存放对象。比如你存一个 int 型数据 1 放入集合中&#xff0c;其实它是自动转换成 Integer类后存入的&#xff0c; Java 中每…

回溯法(1)--装载问题和0-1背包

一、回溯法 回溯法采用DFS&#xff0b;剪枝的方式&#xff0c;通过剪枝删掉不满足条件的树&#xff0c;提高本身作为穷举搜索的效率。 回溯法一般有子集树和排列树两种方式&#xff0c;下面的装载问题和01背包问题属于子集树的范畴。 解空间类型&#xff1a; 子集树&#xff1…

macOS M1安装wxPython报错

macOS12.6.6 M1安装wxPython失败&#xff1a; 报错如下&#xff1a; imagtiff.cpp:37:14: fatal error: tiff.h file not found解决办法&#xff1a; 下载源文件重新编译&#xff08;很快&#xff0c;5分钟全部搞定&#xff09;&#xff0c;分三步走&#xff1a; 第一步&…

Linux 下 12 个最佳 Notepad++ 替代品

Notepadd 是一款完全免费的源代码编辑器&#xff0c;旨在替代 Windows 上的记事本 – 基于 Scintilla 用 C 编写&#xff0c;并实现 Win32 API 和 STL&#xff0c;以确保程序尺寸小且执行速度快 – 这些特性使其成为一个家族开发者中的名字。遗憾的是&#xff0c;没有适用于 Li…

VBA还能这么玩?Word文档一秒自动排版

Hello,各位小伙伴们大家好呀,真的是好久不见了。旅行者1号也才用20个小时回传数据到地球。距离 Yogurt 上次正儿八经的教程推文已经快 700 天了,时间过得真快呀,感谢各位的不离不弃。 这两天群里比较活跃,便上去看看发生了啥事儿,不看不知道,一看,这推文的素材不就来…

DAMNets

方法 体会 实验充分&#xff0c;不愧是ICLR&#xff0c;但作者未提供代码

jvm对象内存划分

写此篇博客源于面试问到内存分配的细节&#xff0c;然后不明白问的是什么。回过头发现以前看过这块内容&#xff0c;只是有些印象&#xff0c;但是无法描述清楚。 额外概念了解 jvm内存空间是逻辑上连续的虚拟地址空间&#xff08;虚拟内存中的概念&#xff09;映射到物理内存…

【C++指针】函数返回指针类型 与 函数返回引用类型(关于获取局部变量的操作)

错误示范 #include <bits/stdc.h> using namespace std;int* RetPtr(void) { //函数返回指针类型int tempData1 1; //函数执行完后&#xff0c;这个变量的生命周期结束&#xff0c;变量的内存被系统收回cout << "第一个函数中值的地址为&#xff…