React性能优化

作者:whuhewei日期:2026/4/13

React应用在复杂场景下容易出现渲染性能瓶颈,合理优化能显著提升用户体验。React性能优化手段的核心在于减少不必要的渲染、控制资源加载和合理使用缓存机制

1. 使用 React.memo 避免子组件无意义重渲染

当父组件更新时,即使子组件props未变,也会默认重新渲染。React.memo可缓存组件输出,仅在props变化时重新更新。

示例Demo:

1import React, { useState } from "react";
2
3const ExpensiveComponent = React.memo(({ count }) => {
4  console.log("ExpensiveComponent 渲染了");
5  return <div>计算结果: {count * 100}</div>;
6});
7
8function App() {
9  const [count, setCount] = useState(0);
10  const [toggle, setToggle] = useState(false);
11
12  return (
13    <div style={{ padding: "20px", fontFamily: "sans-serif" }}>
14      <h2>React.memo 避免子组件重渲染</h2>
15      <button onClick={() => setCount((c) => c + 1)}>增加计数</button>
16      <button onClick={() => setToggle((t) => !t)}>切换状态</button>
17      <p>当前计数: {count}</p>
18      <ExpensiveComponent count={count} />
19      <p style={{ marginTop: "16px" }}>
20        切换状态不会触发 ExpensiveComponent 重渲染
21      </p>
22    </div>
23  );
24}
25
26export default App;
27

在这里插入图片描述
附上codesandbox链接:react-memo
关键点:React.memo默认做浅比较,适用于props为基本类型或不变对象的场景。

2. 使用 useMemo 缓存昂贵计算

对复杂计算(如过滤、排序、数学运算)使用useMemo避免每次渲染都重新执行。

示例Demo:

1import React, { useState, useMemo } from "react";
2
3function ExpensivePrimeCounter() {
4  const [limit, setLimit] = useState(0);
5  const [toggle, setToggle] = useState(false);
6
7  // 模拟昂贵计算:计算小于 limit 的质数个数
8  const primeCount = useMemo(() => {
9    console.log("✅ 重新计算质数个数(未被缓存)");
10    let count = 0;
11    for (let i = 2; i <= limit; i++) {
12      let isPrime = true;
13      for (let j = 2; j * j <= i; j++) {
14        if (i % j === 0) {
15          isPrime = false;
16          break;
17        }
18      }
19      if (isPrime) count++;
20    }
21    return count;
22  }, [limit]); // 仅当 limit 变化时重新计算
23
24  return (
25    <div
26      style={{
27        padding: "2rem",
28        fontFamily: "sans-serif",
29        maxWidth: "500px",
30        margin: "0 auto",
31      }}
32    >
33      <h2>质数计数器</h2>
34      <p>
35        当前上限:<strong>{limit}</strong>
36      </p>
37      <p>
38        小于 {limit} 的质数个数:<strong>{primeCount}</strong>
39      </p>
40      <button
41        onClick={() => setLimit((c) => c + 1)}
42        style={{ margin: "0.5rem" }}
43      >
44        增加上限
45      </button>
46      <button onClick={() => setToggle((t) => !t)}>切换状态</button>
47      <p style={{ fontSize: "0.8rem", color: "#666" }}>
48        注意:仅当上限变化时,质数计算才会重新执行 —— 缓存生效!
49      </p>
50    </div>
51  );
52}
53
54export default ExpensivePrimeCounter;
55

在这里插入图片描述

附上codesandbox链接:react-useMemo
注意:不要滥用useMemo,仅对计算成本高的场景使用(如1000+条数据处理)

3. 使用 useCallback 避免回调函数重新创建

回调函数作为props传递给子组件时,每次渲染都会生成新函数,导致React.memo失效。

示例Demo:

1import React from "react";
2
3const Button = React.memo(({ onClick, label }) => {
4  console.log("Button rendered");
5  return <button onClick={onClick}>{label}</button>;
6});
7
8export default function Parent() {
9  const [count, setCount] = React.useState(0);
10
11  //  每次渲染都创建新函数  Button 会重新渲染
12  // const handleClick = () => setCount(c => c + 1);
13
14  //  使用 useCallback 缓存函数引用
15  const handleClick = React.useCallback(() => {
16    setCount((c) => c + 1);
17  }, []);
18
19  return (
20    <div>
21      <p>Count: {count}</p>
22      <Button label="Increment" onClick={handleClick} />
23    </div>
24  );
25}
26

附上codesandbox链接:react-useCallback
useCallback与React.memo配合使用,是优化组件树的关键组合。

4. 虚拟滚动:渲染大量列表时只渲染可见项

对长列表(如1000+项)使用虚拟滚动,避免DOM节点爆炸。

1import React from 'react';
2import { FixedSizeList as List } from 'react-window';
3
4const Row = ({ index, style }) => (
5  <div style={style}>
6    Item {index}
7  </div>
8);
9
10function LongList({ items }) {
11  return (
12    <List
13      height={400}
14      itemCount={items.length}
15      itemSize={35}
16      width="100%"
17    >
18      {Row}
19    </List>
20  );
21}
22

需安装依赖:react-windowreact-virtualized
性能提升:从渲染1000个DOM节点 → 仅渲染10~20个可见节点

5. 懒加载组件:按需加载非关键模块

使用React.lazy + Suspense实现代码分割,减少首屏加载体积。

1import React, { lazy, Suspense } from 'react';
2
3const HeavyComponent = lazy(() => import('./HeavyComponent'));
4
5function App() {
6  return (
7    <div>
8      <h1>Dashboard</h1>
9      <Suspense fallback={<div>Loading...</div>}>
10        <HeavyComponent />
11      </Suspense>
12    </div>
13  );
14}
15

适用于:弹窗、配置页、图标组件等非首屏内容
可结合webpack实现自动代码分割,SSR模式下可以使用@loadable/component

6. 使用React DevTools分析渲染性能

安装 React DevTools 浏览器插件,启用“Highlight updates when components render”功能,直观看到哪些组件被不必要地重渲染。

总结

优化手段适用场景是否推荐
React.memo子组件props稳定强烈推荐
useMemo复杂计算、昂贵函数推荐
useCallback回调传给memoized子组件推荐
虚拟滚动长列表(>500项)必须使用
React.lazy/@loadable/component非首屏组件推荐

不要过早优化。先保证功能正确,再用工具定位瓶颈,针对性优化。


React性能优化》 是转载文章,点击查看原文


相关推荐


PHP $_GET 变量详解
froginwe112026/4/5

PHP $_GET 变量详解 引言 PHP $_GET 变量是 PHP 中用于处理 URL 查询字符串参数的一个内置数组。在 Web 开发中,$_GET 变量经常用于收集来自表单的数据或者从 URL 中提取信息。本文将详细介绍 PHP $_GET 变量的基本用法、操作方法和注意事项。 一、$_GET 变量简介 在 PHP 中,$_GET 是一个超级全局变量,用于存储通过 URL 传递的参数。这些参数以名值对的形式出现在 URL 中,如 http://www.example.com/?ke


go实战案例:如何基于 Consul 给微服务添加服务注册与发现?
五年小兵勇闯互联网2026/3/27

在单体应用向微服务架构演进的过程中,原本的巨石型应用会按照业务需求被拆分成多个微服务,每个微服务会提供特定的功能,并可能依赖于其他的微服务。每个微服务实例都可以动态部署,服务实例之间的调用通过轻量级的远程调用方式(HTTP、消息队列等)实现,它们之间通过预先定义好的接口进行访问。         由于服务实例是动态部署的,每个服务实例的地址和服务信息都可能动态变化,这就势必需要一个中心化的组件对各个服务实例的信息进行管理,该组件管理了各个部署好的服务实例元数据,包括服务名、IP地址、端口号、服务


VMware虚拟机CentOS磁盘扩容完整指南(解决growpart报错 & LVM扩容)
Microi风闲2026/3/19

文章目录 前言✨一、环境与背景二、第一阶段:VMware 层面扩容三、第二阶段:CentOS 系统内部扩容方法一:标准LVM扩容流程(推荐)方法二:解决 growpart 报错方案(备用) 四、总结与注意事项 前言✨ 在日常开发和运维中,我们经常遇到 VMware 虚拟机磁盘空间不足的问题。本文记录了如何为一台正在运行的 CentOS 7 虚拟机安全地扩容磁盘空间的全过程。本次操作不仅涵盖了标准的扩容步骤,还重点解决了实际操作中可能遇到的两个关键问题: growpart


OpenClaw实战-NAS配置从0到1详细教程及踩坑记录
可夫小子2026/3/11

💡 大家好,我是可夫小子,关注AI编程、AI自动化和自媒体。 背景 我去年在自己Macbook上就已经安装了Openclaw了,当时基本就是一行命令,比较顺利。经过这两个月,Openclaw版本经历了很多更新,当时的安装教程有些过时了。最近,我需要在一台群晖的Nas部署Openclaw,硬是花了两天时间才完成。我把整个详细的部署过程,一些踩坑经历用图文记录下来,就有这篇包含30多张截图的图文。 方案说明 在Nas安装Openclaw,主要有三种方案来实现 直接通过官方脚本,安装到Nas物


NineData 迁移评估功能正式上线
NineData2026/3/3

做过数据库迁移的人,应该都有过类似经历:明明方案写得挺好,时间排得也挺满,但心里一直不踏实。因为真正的问题,往往不是工具能不能迁,而是迁过去以后还能不能跑。 NineData 这次做的迁移评估功能,本质上就只做一件事:提前把不确定性拆开,摊在你面前。 NineData 的一份体检报告,把风险摊在桌面上 异构迁移真正需要关注的是:要改多少?哪些能改?哪些根本不能动? 下面来列一列 NineData 能做哪些事情。 一、对象兼容性评估:哪些能直接迁,哪些一定要改 系统会自动分析源库和目标库的对象差异


AI 系统架构
lizhongxuan2026/2/23

AI 系统看起来很复杂,但核心可以压缩成三句话: 尽量少搬数据:很多时候不是算不动,而是数据搬运太慢。 尽量提高有效计算密度:让硬件更多时间在做有价值的乘加计算。 尽量重叠计算与通信:训练和推理都要避免“设备空等”。 换句话说,AI 性能问题本质上是 计算(Compute)+ 访存(Memory)+ 通信(Communication) 的协同问题。 1. AI 系统栈 层级主要职责典型问


Flutter三方库适配OpenHarmony【apple_product_name】异步调用与错误处理
淼学派对2026/2/14

前言 欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net 本文将围绕 apple_product_name 的实际 API,从 Future 基础到全局错误兜底,给出一套完整的异步调用与错误处理方案。 先给出结论式摘要: 所有 API 返回 Future:getMachineId()、getProductName()、lookup() 都是异步的,必须 await 或 .then()三类异常要分层捕获:PlatformExc


基于uview-pro的u-dropdown扩展自己的dropdown组件
LC同学479812026/2/6

基于uview-pro的u-dropdown扩展自己的dropdown组件 uview-pro的u-dropdown只能是菜单,且只能向下展开,当前组件采用它的核心逻辑,去除多余逻辑,兼容上/下展开,以及自定义展示的内容,不再局限于菜单形式 import type { ExtractPropTypes, PropType } from 'vue'; import { baseProps } from 'uview-pro/components/common/props'; /** * u-


🔥别再用递归了!WeakMap 的影子索引“让树不再是树!”
vilan_微澜2026/1/28

一、前言 大家好,我是微澜。今天来分享一个基于 WeakMap 实现的快速对树形结构数据进行增删改查操作的useTree hook函数,它是基于JavaScript 的 WeakMap 特性,在不改动原始数据的前提下,实现了一套 O(1) 查找的影子索引结构,这个影子其实就是对象的引用地址,让树形数据操作像操作数组一样简单! 二、为什么选择 WeakMap? 1. 非侵入性 (Non-invasive) 通过 WeakMap 在内存中构建了一套 Node -> Parent 的映射。原始数据对象


【Python爬虫实战】用 Flet 把爬虫做成手机 App
MoonPointer-Byte2026/1/18

有没有想过,把你写的爬虫装进手机里? 比如: 想听歌时,后台自动爬取音乐的资源并播放; 想搜图时,后台自动爬取 高清图接口并下载; 想看人时,一键聚合搜索社交用户数据。 今天我们将实战一个MoonMusic。它的核心不是 UI,而是强大的异步数据采集层。 🔧 核心技术栈 数据采集 (Crawler): httpx (异步 HTTP 请求), BeautifulSoup4 (HTML 解析) 并发控制 (Concurrency): asyncio (协程调度) 数据可视

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 XYZ博客