React 组件性能优化

发布于:2024-05-03 ⋅ 阅读:(26) ⋅ 点赞:(0)

React 组件性能优化的核心减少渲染真实 DOM 节点的频率,减少 Virtual DOM 比对的频率。

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

window 注册的全局事件, 以及定时器

useEffect(()=>{
	return ()=>{
		// do something
		clearTimeout(tiemr)
		 window.removeEventListener('xxx', calback)
	}
},[])

2. PureComponent

  1. 什么是纯组件
    纯组件会对组件输入数据进行浅层比较,如果当前输入数据和上次输入数据相同组件不会重新渲染
  2. 什么是浅层比较
    比较引用数据类型在内存中的引用地址是否相同,比较基本数据类型值是否相同
  3. 如何实现纯组件
    类组件继承 PureComponent 类,函数组件使用 memo 方法
  4. 为什么不直接进行 diff 操作, 而是要先进行浅层比较,浅层比较难道没有性能消耗吗?
    和进行 diff 比较操作相比,浅层比较将消耗更少的性能。diff 操作会重新遍历整颗 virtualDOM 树, 而浅层比较只操作当前组件的 state 和 props。

3. shouldComponentUpdate

纯组件只能进行浅层比较,要进行深层比较,使用 shouldComponentUpdate,它用于编写自定义比较逻辑。

返回 true 重新渲染组件,返回 false 阻止重新渲染。

函数的第一个参数为 nextProps, 第二个参数为 nextState.

 shouldComponentUpdate(nextProps, nextState) {
    if (this.state.name !== nextState.name || this.state.age !== nextState.age) {
      return true
    }
    return false
  }

4. React.memo

为 memo 传递比较逻辑

使用 memo方法自定义比较逻辑,用于执行深层比较。

比较函数的第一个参数为上一次的 props, 比较函数的第二个参数为下一次的 props, 比较函数返回 true, 不进行渲染, 比较函数返回 false, 组件重新渲染.

    const ShowPersonMemo = memo(ShowPerson, comparePerson)
   
   function comparePerson(prevProps, nextProps) {
     if (
       prevProps.person.name !== nextProps.person.name ||
       prevProps.person.age !== nextProps.person.age
     ) {
       return false
     }
     return true
   }

5. 使用组件懒加载

使用组件懒加载可以减少 bundle 文件大小, 加快组件呈递速度.

  1. 路由组件懒加载
 import React, { lazy, Suspense } from "react"
 import { BrowserRouter, Link, Route, Switch } from "react-router-dom"
 // 打包时生成对应名字的chunk
 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>
       // 组件未加载完成展示loading
         <Suspense fallback={<div>Loading</div>}>
           <Route path="/" component={Home} exact />
           <Route path="/list" component={List} />
         </Suspense>
       </Switch>
     </BrowserRouter>
   )
 }
    
 export default App
  1. 根据条件进行组件懒加载

    适用于组件不会随条件频繁切换

    import React, { lazy, Suspense } from "react"
    
    function App() {
      let LazyComponent = null
      if (true) {
        LazyComponent = lazy(() => import(/* webpackChunkName: "Home" */ "./Home"))
      } else {
        LazyComponent = lazy(() => import(/* webpackChunkName: "List" */ "./List"))
      }
      return (
        <Suspense fallback={<div>Loading</div>}>
          <LazyComponent />
        </Suspense>
      )
    }
    
    export default App
    

6. 使用 Fragment 避免额外标记

7. 不要使用内联函数定义

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

9. 类组件中的箭头函数

10. 避免使用内联样式属性

11. 优化条件渲染

12. 为组件创建错误边界

错误边界涉及到两个生命周期函数, 分别为 getDerivedStateFromErrorcomponentDidCatch.
– getDerivedStateFromError 为静态方法, 方法中需要返回一个对象, 该对象会和state对象进行合并, 用于更改应用程序状态.

– componentDidCatch 方法用于记录应用程序错误信息. 该方法的参数就是错误对象.
ErrorBoundaries.js

import React from "react"
import App from "./App"
export default class ErrorBoundaries extends React.Component {
  constructor() {
    super()
    this.state = {
      hasError: false
    }
  }
  componentDidCatch(error) {
    console.log("componentDidCatch")
  }
  static getDerivedStateFromError() {
    console.log("getDerivedStateFromError")
    return {
      hasError: true
    }
  }
  render() {
    if (this.state.hasError) {
      return <div>发生了错误</div>
    }
    return <App />
  }
}

App.js

import React from "react"
export default class App extends React.Component {
  render() {
    // throw new Error("lalala")
    return <div>App works</div>
  }
}

index.js

import React from "react"
import ReactDOM from "react-dom"
import ErrorBoundaries from "./ErrorBoundaries"
ReactDOM.render(<ErrorBoundaries />, document.getElementById("root"))

注意: 错误边界不能捕获异步错误, 比如点击按钮时发生的错误.

13. 避免数据结构突变

14. 依赖优化

主要是对包进行优化
参考:重构之路:webpack打包体积优化(超详细)


网站公告

今日签到

点亮在社区的每一天
去签到