欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 会展 > 【react】常见的性能优化 1

【react】常见的性能优化 1

2025/2/6 21:09:10 来源:https://blog.csdn.net/m0_64455070/article/details/144849877  浏览:    关键词:【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 的引入。

码字不易,大佬们点点赞

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com