【react】常见的性能优化 1

目录

常见的 React 性能优化手段

1. 使用 useMemo 和 useCallback 缓存数据和函数

2. 使用 React.memo 缓存组件

3. 组件懒加载

4. 合理使用 key

5. 在组件销毁时清除定时器/事件

6. 使用 Suspense 和 Lazy 拆分组件

7. 使用 Fragment 避免额外标记

8. 避免使用内联函数

9. 避免使用内联样式

10. 优化渲染条件

11. 为组件创建错误边界

12. 组件卸载前进行清理操作

13. 使用 PureComponent

14. 使用 shouldComponentUpdate

15. 在构造函数中进行函数 this 绑定

16. 类组件中的箭头函数

17. 避免数据结构突变

18. 依赖优化

常见的 React 性能优化手段

在开发 React 应用时,性能优化是确保应用高效运行的关键。以下是常见的 React 性能优化手段,并附带代码示例和解释。

1. 使用 useMemo 和 useCallback 缓存数据和函数

useMemo 和 useCallback 是 React 提供的 Hooks,用于缓存计算结果和函数引用,避免不必要的重新渲染。

示例:

import React, { useState, useMemo, useCallback } from 'react';const data = {userName: '张三',age: 19,fav: '篮球、排球',
};const getUserInfo = () => {return {...data,random: Math.random(),};
};function Case2() {const [count, setCount] = useState(0);// 使用 useMemo 缓存数据const userInfo = useMemo(() => getUserInfo(), []);// 使用 useCallback 缓存函数const handleClick = useCallback(() => {setCount(count + 1);}, [count]);return (<div><div>姓名:{userInfo.userName}</div><div>年龄:{userInfo.age}</div><div>爱好:{userInfo.fav}</div><div>随机数: {userInfo.random}</div><div>当前页面渲染次数: {count}</div><button onClick={handleClick}>刷新渲染组件</button></div>);
}

解释:useMemo 确保 getUserInfo 的结果只在首次渲染时计算一次。

   useCallback 确保 handleClick 函数的引用不会在每次渲染时都重新创建。

2. 使用 React.memo 缓存组件

React.memo 类似于 shouldComponentUpdate,当 props 没有变化时,不会重新渲染组件,从而提高性能。

示例:

import React from 'react';
import { Button } from 'antd';const BasicButton = (props) => {return <Button {...props}></Button>;
};export default React.memo(BasicButton, (oldProps, newProps) => {return oldProps === newProps; // true - 不更新 false - 更新
});

解释:React.memo 接收一个比较函数,只有当 props 发生变化时才会重新渲染组件。

3. 组件懒加载

使用组件懒加载可以减少初始 bundle 文件大小,加快组件加载速度。

示例:

import React, { lazy, Suspense } from 'react';
import { BrowserRouter, Link, Route, Switch } from 'react-router-dom';const Home = lazy(() => import(/* webpackChunkName: "Home" */ './Home'));
const List = lazy(() => import(/* webpackChunkName: "List" */ './List'));function App() {return (<BrowserRouter><Link to="/">Home</Link><Link to="/list">List</Link><Switch><Suspense fallback={<div>Loading</div>}><Route path="/" component={Home} exact /><Route path="/list" component={List} /></Suspense></Switch></BrowserRouter>);
}export default App;

解释:lazy 动态导入组件,Suspense 提供加载状态。

4. 合理使用 key

在 map 循环中尽量使用唯一的标识作为 key,避免使用 index 作为 key,方便复用组件。

示例:

import React from 'react';const list = [{ id: 1, name: '张三' },{ id: 2, name: '李四' },{ id: 3, name: '王五' },
];function Case3() {return (<div>{list.map((item) => (<div key={item.id}>{item.name}</div>))}</div>);
}export default Case3;

解释:使用 id 作为 key,确保每个元素的唯一性。

5. 在组件销毁时清除定时器/事件

组件卸载时清除相关事件、定时器,防止内存泄漏。

示例:

import React, { useEffect, useState } from 'react';function Case1() {const [count, setCount] = useState(0);useEffect(() => {const timer = setInterval(() => {setCount(count + 1);}, 1000);return () => {clearInterval(timer);};}, [count]);return <div>{count}</div>;
}export default Case1;

解释:useEffect 返回的清理函数会在组件卸载时执行,清除定时器。

6. 使用 Suspense 和 Lazy 拆分组件

通过 Suspense 和 Lazy 实现按需加载组件,提升首屏加载速度。

示例:

import React, { lazy } from 'react';
import ReactDOM from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';const LearnReactOptimize = lazy(() => import('./pages/LearnReactOptimize'));const LazyBoundary = (WrapComp) => (<Suspense fallback={<div>loading....</div>}><WrapComp /></Suspense>
);const routeConfig = createBrowserRouter([{path: '/LearnReactOptimize',element: LazyBoundary(LearnReactOptimize),},{path: '/',element: <App />,},
]);const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<React.StrictMode><RouterProvider router={routeConfig} /></React.StrictMode>,
);

解释:Suspense 提供加载状态,Lazy 动态导入组件。

7. 使用 Fragment 避免额外标记

通过 Fragment 减少不必要的标签,简化 DOM 结构。

示例:

import React from 'react';// bad
function AppBad() {return (<div><div>1</div><div>2</div></div>);
}// good
function AppGood() {return (<><div>1</div><div>2</div></>);
}

解释:Fragment (<>...</>) 不会生成额外的 DOM 元素。

8. 避免使用内联函数

避免在 JSX 中使用内联函数,以减少不必要的函数创建。

示例:

import React from 'react';// bad
function AppBad() {const handleClick = () => {console.log('click');};return <div onClick={() => handleClick()}>App</div>;
}// good
function AppGood() {const handleClick = () => {console.log('click');};return <div onClick={handleClick}>App</div>;
}

解释:内联函数每次渲染都会创建新的函数实例,导致不必要的性能开销。

9. 避免使用内联样式

避免使用内联样式,将样式提取到 CSS 文件中,减少 JavaScript 执行时间。

示例:

import React from 'react';
import './App.css'; // 引入外部 CSS 文件function App() {return <div className="app-style">App works</div>;
}export default App;

解释:将样式提取到外部 CSS 文件中,减少 JavaScript 执行时间。

10. 优化渲染条件

避免不必要的渲染,确保组件只在必要时更新。

示例:

import React, { useState, useEffect } from 'react';function App() {const [count, setCount] = useState(0);const [name] = useState("张三");useEffect(() => {setInterval(() => {setCount(prev => prev + 1);}, 1000);}, []);return (<div>{count}<ShowNameMemo name={name} /></div>);
}function ShowName({ name }) {console.log("showName render...");return <div>{name}</div>;
}const ShowNameMemo = React.memo(ShowName);export default App;

解释:使用 React.memo 防止不必要的重新渲染。

11. 为组件创建错误边界

捕获子组件中的错误,防止整个组件树崩溃。

示例:

import React from 'react';class ErrorBoundary extends React.Component {constructor(props) {super(props);this.state = { hasError: false };}static getDerivedStateFromError(error) {return { hasError: true };}componentDidCatch(error, errorInfo) {console.log(error, errorInfo);}render() {if (this.state.hasError) {return <h1>Something went wrong.</h1>;}return this.props.children;}
}export default ErrorBoundary;

解释:ErrorBoundary 捕获子组件中的错误,显示降级 UI。

12. 组件卸载前进行清理操作

确保组件卸载时清理定时器、事件监听等资源。

示例:

import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';const App = () => {const [count, setCount] = useState(0);useEffect(() => {let timer = setInterval(() => {setCount(prev => prev + 1);}, 1000);return () => {clearInterval(timer);};}, []);return (<button onClick={() => ReactDOM.unmountComponentAtNode(document.getElementById('root'))}>{count}</button>);
};export default App;

解释:useEffect 返回的清理函数会在组件卸载时执行,清除定时器。

13. 使用 PureComponent

PureComponent 是类组件的优化版本,自动实现浅比较,减少不必要的渲染。

示例:

import React from 'react';class App extends React.Component {constructor(props) {super(props);this.state = {count: 1,};}componentDidMount() {this.setState({ count: 1 });}render() {return (<div><RegularChildComponent count={this.state.count} /><PureChildComponent count={this.state.count} /></div>);}
}class RegularChildComponent extends React.Component {render() {console.log('RegularChildComponent render');return <div>{this.props.count}</div>;}
}class PureChildComponent extends React.PureComponent {render() {console.log('PureChildComponent render');return <div>{this.props.count}</div>;}
}export default App;

解释:PureComponent 自动实现浅比较,减少不必要的渲染。

14. 使用 shouldComponentUpdate

手动控制组件是否需要更新。

示例:

import React from 'react';export default class App extends React.Component {constructor() {super();this.state = { name: '张三', age: 20, job: 'waiter' };}componentDidMount() {setTimeout(() => this.setState({ job: 'chef' }), 1000);}shouldComponentUpdate(nextProps, nextState) {if (this.state.name !== nextState.name || this.state.age !== nextState.age) {return true;}return false;}render() {console.log('rendering');let { name, age } = this.state;return <div>{name} {age}</div>;}
}

解释:shouldComponentUpdate 控制组件是否需要更新。

15. 在构造函数中进行函数 this 绑定

确保类方法中的 this 指向正确。

示例:

import React from 'react';export default class App extends React.Component {constructor() {super();this.handleClick = this.handleClick.bind(this);}handleClick() {console.log(this);}render() {return <button onClick={this.handleClick}>按钮</button>;}
}

解释:构造函数中绑定 this,确保方法中的 this 指向正确。

16. 类组件中的箭头函数

使用箭头函数避免 this 绑定问题。

示例:

import React from 'react';export default class App extends React.Component {handleClick = () => console.log(this);render() {return <button onClick={this.handleClick}>按钮</button>;}
}

解释:箭头函数自动绑定 this,避免手动绑定。

17. 避免数据结构突变

保持组件中 props 和 state 的数据结构一致,避免突变。

示例:

import React, { Component } from 'react';export default class App extends Component {constructor() {super();this.state = {employee: {name: '张三',age: 20,},};}render() {const { name, age } = this.state.employee;return (<div>{name}{age}<buttononClick={() =>this.setState({...this.state,employee: {...this.state.employee,age: 30,},})}>change age</button></div>);}
}

解释:使用扩展运算符避免直接修改对象。

18. 依赖优化

优化第三方库的引入,减少打包体积。

示例:

  1. 安装依赖:

    yarn add react-app-rewired customize-cra lodash babel-plugin-lodash
  2. 创建 config-overrides.js

    const { override, useBabelRc } = require('customize-cra');module.exports = override(useBabelRc());
  3. 修改 package.json

    "scripts": {"start": "react-app-rewired start","build": "react-app-rewired build","test": "react-app-rewired test --env=jsdom","eject": "react-scripts eject"
    }
  4. 创建 .babelrc

    {"plugins": ["lodash"]
    }
  5. 使用 Lodash:

    import React from 'react';
    import _ from 'lodash';function App() {console.log(_.chunk(['a', 'b', 'c', 'd'], 2));return <div>App works</div>;
    }export default App;

解释:使用 react-app-rewired 和 customize-cra 覆盖默认配置,babel-plugin-lodash 优化 Lodash 的引入。

码字不易,大佬们点点赞

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/65837.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Promise实现原理解析,及实现方法。

Promise原理解析 Promise的介绍原理分析源码实现发布部分全部代码订阅部分基础代码简单发布订阅完整代码测试订阅能力链式调用的实现完整链式调用代码链式调用Promise完整功能代码 Promise的介绍 一&#xff0c;Promise的理解 在JavaScript中&#xff0c;Promise是一种用于处理…

http报头解析

http报文 http报文主要有两类是常见的&#xff0c;第一类是请求报文&#xff0c;第二类是响应报文&#xff0c;每个报头除了第一行&#xff0c;都是采用键值对进行传输数据&#xff0c;请求报文的第一行主要包括http方法&#xff08;GET&#xff0c;PUT&#xff0c; POST&#…

【日常开发】Git Stash使用技巧

文章目录 引言一、git stash 基础命令&#xff08;一&#xff09;存储当前工作区的修改&#xff08;二&#xff09;查看存储列表 二、查看存储的内容&#xff08;一&#xff09;查看特定存储的详细内容&#xff08;二&#xff09;查看特定存储修改的文件列表 三、恢复存储的修改…

微服务保护-sentinel

为什么要有微服务保护&#xff1f; 微服务保护是为了避免微服务雪崩而出现的&#xff0c;每个微服务能处理的请求是有限的&#xff0c;如果一个微服务出现问题导致一个请求进入微服务的时间太久&#xff0c;就会导致大量去请求停滞在微服务内部&#xff0c;这样就会过分占用系统…

【Redis】Redis 典型应用 - 缓存 (cache)

目录 1. 什么是缓存 2. 使用 Redis 作为缓存 3. 缓存的更新策略 3.1 定期生成 3.2 实时生成 4. 缓存的淘汰策略 5. 缓存预热, 缓存穿透, 缓存雪崩 和 缓存击穿 关于缓存预热 (Cache preheating) 关于缓存穿透 (Cache penetration) 关于缓存雪崩 (Cache avalanche) 关…

关于easy-es对时间范围查询遇到的小bug

前言&#xff1a;在使用easy-es之前作为一个小白的我只有es原生查询的基础&#xff0c;在自己通过查看官方文档自学easy-es遇到了一个挫折&#xff0c;其他的还好语法和MybatisPlus差不多&#xff0c;正以为我觉得很快就能入手&#xff0c;在对时间范围的判断就给我当头一棒&am…

Python读取TIF文件

在Python中&#xff0c;逐帧读取TIFF文件&#xff08;尤其是多页TIFF文件&#xff09;可以使用tifffile库或Pillow库。以下是两种方法的示例&#xff1a; 方法 1&#xff1a;使用 tifffile 逐帧读取 tifffile 是一个专门用于处理TIFF文件的库&#xff0c;支持多页TIFF文件的逐…

只谈C++11新特性 - 显式转换函数

显式转换函数 背景与问题 在 C11 之前&#xff0c;explicit 关键字只能用于构造函数。其作用是阻止构造函数在需要隐式转换时被调用。例如&#xff1a; 示例问题&#xff08;C11 之前的 explicit 用法&#xff09; #include <iostream>class Example { public:explic…

从0到机器视觉工程师(一):机器视觉工业相机总结

目录 相机的作用 工业相机 工业相机的优点 工业相机的种类 工业相机知名品牌 光源与打光 打光方式 亮暗场照明 亮暗场照明的应用 亮暗场照明的区别 前向光漫射照明 背光照明 背光照明的原理 背光照明的应用 同轴光照明 同轴光照明的应用 总结 相机的作用 相机…

HTML——53. 创建表单

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>创建表单</title></head><body><!--form标签用于创建一个表单&#xff0c;会将里面的内容一起发送服务器&#xff0c;其结构类似于表格--><!--表…

逐行讲解大模型流式输出 streamer 源码

目录 简介TextStreamer 基础流式输出TextIterateStreamer 迭代器流式输出本地代码模型加载并前端展示streamlit 输出显示gradio 输出显示 vllm 部署模型并前端展示streamlit 输出显示gradio 输出显示 备注 简介 本文详细讲解了大模型流式输出的源码实现&#xff0c;包括TextSt…

java_使用阿里云oss服务存储图片

什么情况下可以使用阿里云oss服务存储图片&#xff1f; 对图片的访问速度有高要求时使用&#xff0c;方便用户快速的&#xff08;比如在网页页面中&#xff09;访问到图像 参考&#xff1a;41 尚上优选项目-平台管理端-商品信息管理模块-阿里云OSS介绍_哔哩哔哩_bilibili 1.…

第5章 共享内存范式:C语言层面

5.1OpenMP 5.1.1OpenMP的介绍 OpenMP三个原则 5.2OpenMP的使用 编译制导指令以#pragma omp 开始&#xff0c;后边跟具体的功能指令&#xff0c;格式如:#pragma omp 指令[子句[,子句].]。常用的功能指令如下: 5.2.1编译制导 5.2.2API和环境变量 具体案例-邻接矩阵 // 本代码…

全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之循环结构(for循环语句)(七)

实战训练—鸡兔同笼 问题描述&#xff1a; 一个笼子里面关了鸡和兔子&#xff08;鸡有2只脚&#xff0c;兔子有4只脚&#xff0c;没有例外&#xff09;。已经知道了笼子里面脚的总数为a&#xff0c;问笼子里面至少有多少只动物&#xff0c;至多有多少只动物。 输入格式&…

web 开发全局覆盖文件上传身份验证漏洞利用

全局覆盖 首先认识全局变量和局部变量 再一个就是知道全局变量是全局使用的并且有个特点就是可以覆盖 这个就是全局变量我们输出一下发现 z居然等于函数内的计算值 把我们原来定义的全局变量 $z给覆盖了 看一下局部变量 这个时候 z就不会被覆盖 <?php $x1; $y2; …

No.2十六届蓝桥杯备战|练习题4道|数据类型|字符型|整型|浮点型|布尔型|signed|unsigned(C++)

B2002 Hello,World! - 洛谷 #include <iostream> using namespace std; int main() { cout << "Hello,World!" << endl; return 0; }打印飞机 #include <iostream> using namespace std;int main() {cout << " …

46. Three.js案例-创建颜色不断变化的立方体模型

46. Three.js案例-创建颜色不断变化的立方体模型 实现效果 知识点 Three.js基础组件 WebGLRenderer THREE.WebGLRenderer是Three.js提供的用于渲染场景的WebGL渲染器。它支持抗锯齿处理&#xff0c;可以设置渲染器的大小和背景颜色。 构造器 antialias: 是否开启抗锯齿&am…

5.系统学习-PyTorch与多层感知机

PyTorch与多层感知机 前言PyTroch 简介张量&#xff08;Tensor&#xff09;张量创建张量的类型数据类型和 dtype 对应表张量的维度变换&#xff1a;张量的常用操作矩阵或张量计算 Dataset and DataLoaderPyTorch下逻辑回归与反向传播数据表格 DNN&#xff08;全连结网络&#x…

WPF中的Microsoft XAML Behaviors包功能详解

什么是XAML Behaviors(行为) XAML Behaviors 提供了一种简单易用的方法&#xff0c;能以最少的代码为 Windows UWP/WPF 应用程序添加常用和可重复使用的交互性。 但是Microsoft XAML Behaviors包除了提供常用的XAML Behaviors之外&#xff0c;还提供了一些Trigger&#xff08…

运维人员的Go语言学习路线

以下是一份更为详细的适合运维人员的Go语言学习路线图&#xff1a; 一、基础环境搭建与入门&#xff08;第 1 - 2 周&#xff09; 第 1 周 环境搭建 在本地开发机和常用的运维服务器环境&#xff08;如 Linux 系统&#xff09;中安装 Go 语言。从官方网站&#xff08;https://…