亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

React中組件優(yōu)化的最佳方案分享

 更新時(shí)間:2023年12月22日 10:57:03   作者:慕仲卿  
React組件性能優(yōu)化可以減少渲染真實(shí)DOM的頻率,以及減少VD比對(duì)的頻率,本文為大家整理了一些有效的React組件優(yōu)化方法,需要的小伙伴可以參考下

核心:減少渲染真實(shí)DOM的頻率,以及減少VD比對(duì)的頻率

1. 組件卸載前執(zhí)行清理操作

  • 注冊(cè)的全局事件
  • 定時(shí)器

證明:在組件掛載之后通過(guò)useEffect中開啟定時(shí)器,銷毀此組件之后,定時(shí)器還是存在的!

基于此,需要在useEffect第一個(gè)形參函數(shù)的返回值中將定時(shí)器清除掉。

2. 通過(guò)純組件來(lái)提升性能

什么是純組件

所謂純組件,就是當(dāng)輸入數(shù)據(jù)發(fā)生改變的時(shí)候,會(huì)將新數(shù)據(jù)和舊數(shù)據(jù)進(jìn)行一次淺層比較,如果淺層比較結(jié)果相同,那么就不會(huì)引起重新渲染。

如何實(shí)現(xiàn)純組件

使用PureComponent類或者memo方法可以實(shí)現(xiàn)純的類或者函數(shù)組件。

驗(yàn)證示例

import React from "react";

export default class App extends React.Component {
  constructor() {
    super();
    this.state = { name: "張三" };
  }

  updateName() {
    setInterval(() => this.setState({ name: "張三" }), 1000);
  }

  componentDidMount() {
    this.updateName();
  }

  render() {
    return (
      <div>
        <RegularComponent name={this.state.name} />
        {/* 這里可能有其他組件或JSX元素 */}
      </div>
    );
  }
}

3. 在類組件中使用shouldComponentUpdate

由于使用PureComponent只能進(jìn)行淺層的比較,所以在類組件中使用shouldComponentUpdate生命周期函數(shù)能夠自定義用戶的比較行為。

此生命周期函數(shù)的返回值是一個(gè)布爾值,如果為true表示需要更新,反之則不需要進(jìn)行更新;此函數(shù)接受兩個(gè)參數(shù),其一是nextProps,另外一個(gè)nextState。分別表示外部和內(nèi)部數(shù)據(jù)。

import React from "react";

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      person: {
        name: "張三",
        age: 20,
        job: "waiter"
      }
    };
  }

  componentDidMount() {
    setTimeout(() => {
      // 這里使用擴(kuò)展運(yùn)算符合并對(duì)象來(lái)確保我們創(chuàng)建了person對(duì)象的一個(gè)新副本
      this.setState({ person: { ...this.state.person, job: "chef" } });
    }, 2000);
  }

  shouldComponentUpdate(nextProps, nextState) {
    // 只在person對(duì)象的name或age屬性發(fā)生變化時(shí)更新組件
    if (this.state.person.name !== nextState.person.name || this.state.person.age !== nextState.person.age) {
      return true;
    }
    return false;
  }

  render() {
    return (
      // 此處根據(jù)你的需求可以添加任何需要顯示的內(nèi)容
      <div>
        Name: {this.state.person.name},
        Age: {this.state.person.age},
        Job: {this.state.person.job}
      </div>
    );
  }
}

4. 通過(guò)函數(shù)式組件React.memo提升性能

父組件的渲染會(huì)引起子組件的渲染

證明示例:

import React, { useState, useEffect } from 'react';

function App() {
  const [name] = useState("張三");
  const [index, setIndex] = useState(0);

  useEffect(() => {
    const intervalId = setInterval(() => {
      setIndex(prev => prev + 1);
    }, 1000);

    // 清除interval,防止內(nèi)存泄漏
    return () => clearInterval(intervalId);
  }, []);

  return (
    <div>
      {index}
      <ShowName name={name} />
    </div>
  );
}

function ShowName({ name }) {
  console.log("rendering ShowName");
  return <div>{name}</div>;
}

export default App;

使用memo優(yōu)化上述代碼

const ShowName = React.memo(function ({ name }) {
  console.log("rendering ShowName");
  return <div>{name}</div>;
})

memo具有第二個(gè)參數(shù),第二個(gè)參數(shù)也是一個(gè)函數(shù),此函數(shù)返回一個(gè)布爾值,其作用是自定義用戶的比較行為;如果返回值是true則表示比較的兩個(gè)對(duì)象(也是此函數(shù)的兩個(gè)入?yún)?,分別為: prevProps和nextProps)是相同的,因此也就不需要重新渲染;否則則需要重新渲染。

import React, { memo, useEffect, useState } from "react";

// 比較函數(shù),用以優(yōu)化渲染
function comparePerson(prevProps, nextProps) {
  if (
    prevProps.person.name !== nextProps.person.name ||
    prevProps.person.age !== nextProps.person.age
  ) {
    return false; // 如果person的name或age改變了,就重新渲染
  }
  return true; // 如果person的name或age沒變,不重新渲染
}

// 用memo包裹的組件,將比較函數(shù)作為第二個(gè)參數(shù)傳入
const ShowPerson = memo(function ShowPerson({ person }) {
  console.log("rendering ShowPerson");
  return (
    <div>
      {person.name} {person.age}
    </div>
  );
}, comparePerson);

function App() {
  const [person, setPerson] = useState({ name: "張三", age: 20, job: "waiter" });

  useEffect(() => {
    const intervalId = setInterval(() => {
      // 更新設(shè)置person狀態(tài)對(duì)象中的job屬性,而不是name或age
      setPerson(prevPerson => ({ ...prevPerson, job: "chef" }));
    }, 1000);

    // 清除interval,防止內(nèi)存泄漏
    return () => clearInterval(intervalId);
  }, []);

  return (
    <div>
      <ShowPerson person={person} />
    </div>
  );
}

export default App;

5. 使用組件的懶加載來(lái)提升組件性能

使用懶加載的組件優(yōu)化的核心邏輯在于減少bundle文件的大小,加快組件的呈現(xiàn)速度。但是,采用懶加載的組件會(huì)被打包到不同的文件中(分包)

路由組件懶加載

import React, { lazy, Suspense } from 'react';
import { BrowserRouter, Link, Route, Switch } from "react-router-dom";

// 使用React的lazy函數(shù)動(dòng)態(tài)導(dǎo)入組件
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包裹Route,并提供fallback來(lái)展示加載狀態(tài)
        <Suspense fallback={<div>Loading...</div>}>
          <Route path="/" component={Home} exact />
          <Route path="/list" component={List} />
        </Suspense>
      </Switch>
    </BrowserRouter>
  );
}

export default App;

代碼分析:

  • lazy 是一個(gè)React函數(shù),它允許你定義一個(gè)動(dòng)態(tài)加載的組件。這里,HomeList組件都是通過(guò)lazy函數(shù)和動(dòng)態(tài)import進(jìn)行定義的。Webpack將這些動(dòng)態(tài)導(dǎo)入的組件分離到不同的代碼塊(chunks),當(dāng)訪問(wèn)對(duì)應(yīng)路由時(shí)才會(huì)加載它們。
  • Suspense組件是React內(nèi)置的一個(gè)組件,它允許你在渲染等待內(nèi)容(如懶加載組件)時(shí)顯示一些回退內(nèi)容。在這個(gè)例子中,回退內(nèi)容是一個(gè)簡(jiǎn)單的<div>Loading...</div>,它會(huì)在懶加載組件被加載和渲染之前顯示。
  • BrowserRouter 是react-router-dom庫(kù)中的組件,它使用HTML5歷史API(pushStatereplaceStatepopstate事件)來(lái)保持UI和URL的同步。
  • Link組件提供聲明式的、可訪問(wèn)的導(dǎo)航的方式。
  • Route是配置路由的基本單元,它將一個(gè)路徑和一個(gè)組件映射起來(lái),當(dāng)路徑匹配時(shí)就會(huì)渲染對(duì)應(yīng)的組件。
  • Switch組件用于渲染第一個(gè)匹配當(dāng)前位置的<Route><Redirect>。

這種方式使得在應(yīng)用啟動(dòng)時(shí)不會(huì)加載所有組件,而是僅在用戶導(dǎo)航到相應(yīng)的路由時(shí)才加載對(duì)應(yīng)的組件,從而優(yōu)化了性能。

根據(jù)某種條件進(jìn)行組件懶加載

使用條件:組件不會(huì)隨著條件頻繁切換的場(chǎng)景下

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避免額外標(biāo)記

那就是:<Fragment></Fragment>

7. 避免使用內(nèi)聯(lián)函數(shù)提升函數(shù)性能

原因:render函數(shù)每次執(zhí)行渲染的時(shí)候都會(huì)重新創(chuàng)建此內(nèi)斂函數(shù)的實(shí)例,導(dǎo)致React在進(jìn)行虛擬DOM的對(duì)比的時(shí)候,同一個(gè)位置的內(nèi)斂函數(shù)并不相等,由此導(dǎo)致兩個(gè)消耗:新的創(chuàng)建需要消耗;舊的回收也需要消耗。

不好的實(shí)踐:

onChange={e=>this.setState({value:e.target.value})}

好的實(shí)踐:

this.handleOnChange = e=>this.setState({value:e.target.value});
...
onChange={handleOnChange}

8. 正確的更正this的指向問(wèn)題

修正this指向問(wèn)題的方法有好幾種,但是通過(guò)對(duì)比下來(lái),最佳實(shí)踐為:

constructor(){
    super();
    this.handleClick = this.handleClick.bind(this);
}

不好的實(shí)踐為:

<Button onClick={this.handleClick.bind(this)}>按鈕</Button>

原因:上述代碼在render執(zhí)行的時(shí)候都會(huì)執(zhí)行一次,重復(fù)次數(shù)多,不像constructor只執(zhí)行一次。

9. 避免在類組件中使用箭頭函數(shù)創(chuàng)建類方法

在類組件中使用箭頭函數(shù)的好處就是完全不用擔(dān)心this的指向問(wèn)題;因?yàn)榧^函數(shù)并不會(huì)改變this的指向。但是我看到過(guò)一句話:this的指向問(wèn)題從來(lái)就不是使用箭頭函數(shù)的原因。因此,并不推薦在類組件中使用箭頭函數(shù)創(chuàng)建方法。

從功利的角度來(lái)看,如果使用箭頭函數(shù)創(chuàng)建類的方法,此方法不會(huì)掛載在原型上,而是作為實(shí)例的一個(gè)屬性。也就是說(shuō)如果此類組件實(shí)例化很多次,那么此方法也會(huì)被實(shí)例化相同次數(shù),這會(huì)造成極大的浪費(fèi)。

因此,在類組件中解決this的最佳實(shí)踐仍然是在構(gòu)造函數(shù)中bind(this)

10. 避免使用內(nèi)聯(lián)樣式屬性

如果在項(xiàng)目中使用如下的代碼,那么在編譯之后,內(nèi)斂的style會(huì)被映射成為js代碼,最后就變成了js創(chuàng)建樣式,導(dǎo)致瀏覽器會(huì)花費(fèi)更多的時(shí)間執(zhí)行腳本和渲染UI,從而降低了性能。

核心問(wèn)題:CSS渲染UI的速度遠(yuǎn)超過(guò)js,因此能不用js操作樣式就不要用!這一點(diǎn)很重要。本質(zhì)上還是js操作DOM很費(fèi)時(shí)間。

不好的實(shí)踐:

fucntion App () {
  return <div style={{backgroundColor: 'red'}}>div</div>
}

11. 對(duì)條件渲染進(jìn)行優(yōu)化

這點(diǎn)主要是針對(duì):頻繁的掛載和卸載組件是一項(xiàng)非常消耗性能的事情 這一事實(shí)提出的優(yōu)化,其本質(zhì)仍然是盡量減少對(duì)DOM的操作

好的實(shí)踐

function App() {
  return (
    <>
      {true && <AdminHeader />}
      <Header />
      <Content />
    </>
  );
}

不好的實(shí)踐

function App() {
  if (true) {
    return (
      <>
        <AdminHeader />
        <Header />
        <Content />
      </>
    );
  } else {
    return (
      <>
        <Header />
        <Content />
      </>
    );
  }
}

第一種做法中,隨著條件的改變,重新渲染的只有AdminHeader組件,而第二種做法三個(gè)組件都會(huì)重新渲染,這也是由于虛擬DOM的對(duì)比策略所決定的。

12. 避免重復(fù)的無(wú)限渲染

避免在componentWillUpdate、componentDidUpdate或者render(是純函數(shù))方法中調(diào)用setState等可以觸發(fā)組件在此渲染的做法。本質(zhì)上是避免render函數(shù)循環(huán)調(diào)用自身。

13. 為組件創(chuàng)建錯(cuò)誤邊界

先說(shuō)不足:錯(cuò)誤邊界本質(zhì)上是一個(gè)組件;但是只能在同步錯(cuò)誤發(fā)生的時(shí)候顯示出來(lái),異步錯(cuò)誤是沒有辦法被錯(cuò)誤邊界響應(yīng)的!

錯(cuò)誤邊界(Error Boundaries)是React的一個(gè)特性,它可以捕獲其子組件樹中JavaScript錯(cuò)誤,記錄這些錯(cuò)誤,并顯示備用UI,而不是讓整個(gè)組件樹崩潰。錯(cuò)誤邊界只能通過(guò)類組件來(lái)實(shí)現(xiàn),因?yàn)樾枰褂蒙芷诜椒?code>componentDidCatch或getDerivedStateFromError。

以下分別介紹在類組件和函數(shù)式組件中如何處理錯(cuò)誤,并舉例說(shuō)明。

類組件中的錯(cuò)誤邊界

在類組件中,你可以定義一個(gè)錯(cuò)誤邊界組件,如下所示:

import React from 'react';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // 當(dāng)子組件拋出異常,這里將會(huì)被調(diào)用,返回新的state
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // 你同樣可以在這里記錄錯(cuò)誤信息
    console.error('ErrorBoundary caught an error', error, info);
  }

  render() {
    if (this.state.hasError) {
      // 當(dāng)發(fā)生錯(cuò)誤時(shí),你可以渲染任何自定義的回退UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

然后你可以像這樣使用ErrorBoundary組件:

<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

這樣,如果MyComponent或者其任何子組件在渲染過(guò)程中發(fā)生JavaScript錯(cuò)誤,ErrorBoundary就會(huì)顯示備用UI,并防止整個(gè)應(yīng)用崩潰。

函數(shù)式組件中的錯(cuò)誤處理

函數(shù)式組件不能直接創(chuàng)建錯(cuò)誤邊界,因?yàn)樗鼈儾恢С?code>componentDidCatch或getDerivedStateFromError這類生命周期方法。然而,你可以在函數(shù)式組件內(nèi)使用hooks來(lái)處理錯(cuò)誤,例如使用useStateuseEffect來(lái)模擬類似的行為。不過(guò),這不是標(biāo)準(zhǔn)的錯(cuò)誤邊界實(shí)現(xiàn),標(biāo)準(zhǔn)的錯(cuò)誤邊界目前只能通過(guò)類組件來(lái)實(shí)現(xiàn)。

但是,你可以通過(guò)將函數(shù)式組件包裹在上面定義的錯(cuò)誤邊界類組件中來(lái)提供錯(cuò)誤捕獲功能。

例如:

function MyFunctionalComponent() {
  useEffect(() => {
    try {
      // 這里是可能會(huì)拋出錯(cuò)誤的代碼
    } catch (error) {
      // 你可以在這里處理錯(cuò)誤,例如設(shè)置狀態(tài)顯示錯(cuò)誤信息
    }
  });

  return (
    // 你的組件返回值
  );
}

// 應(yīng)用錯(cuò)誤邊界
<ErrorBoundary>
  <MyFunctionalComponent />
</ErrorBoundary>

在這個(gè)例子中,任何在MyFunctionalComponent中發(fā)生的錯(cuò)誤都需要自己處理,并不利用錯(cuò)誤邊界來(lái)捕獲。但是被ErrorBoundary包裹的話,任何子組件樹中的錯(cuò)誤仍然可以被ErrorBoundary捕獲。

總而言之,如果你希望在函數(shù)式組件中享有錯(cuò)誤邊界的保護(hù),你需要將函數(shù)式組件放入一個(gè)可以作為錯(cuò)誤邊界的類組件之內(nèi)。 直到React提供函數(shù)式組件的官方錯(cuò)誤邊界支持,這種方式將是常規(guī)的做法。

總結(jié)一下

本質(zhì)上還是:條件渲染;只不過(guò)引發(fā)條件變化的源在于:是否發(fā)生了錯(cuò)誤!

14. 避免數(shù)據(jù)結(jié)構(gòu)的突變

結(jié)論:組件中的props和state的數(shù)據(jù)結(jié)構(gòu)應(yīng)該保持一致,數(shù)據(jù)結(jié)構(gòu)的突變會(huì)導(dǎo)致輸出不一致??!這一點(diǎn)在state的層數(shù)比較深的時(shí)候一定要引起額外注意!

onClick={() =>
  this.setState({
    ...this.state,
    employee: {
      ...this.state.employee,
      age: 30
    }
  })
}

15. 優(yōu)化依賴項(xiàng)大小

有一些庫(kù)不支持動(dòng)態(tài)加載,比如說(shuō)lodash。但是lodash提供了一些插件,使用這些插件也能夠?qū)崿F(xiàn)按需加載相同的效果,從而顯著的減少最終打包成的bundle的大小。

以上就是React中組件優(yōu)化的最佳方案分享的詳細(xì)內(nèi)容,更多關(guān)于React組件優(yōu)化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React?Hooks useReducer?逃避deps組件渲染次數(shù)增加陷阱

    React?Hooks useReducer?逃避deps組件渲染次數(shù)增加陷阱

    這篇文章主要介紹了React?Hooks?之?useReducer?逃避deps后增加組件渲染次數(shù)的陷阱詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 詳解React之父子組件傳遞和其它一些要點(diǎn)

    詳解React之父子組件傳遞和其它一些要點(diǎn)

    這篇文章主要介紹了詳解React之父子組件傳遞和其它一些要點(diǎn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • React+Typescript創(chuàng)建項(xiàng)目的實(shí)現(xiàn)步驟

    React+Typescript創(chuàng)建項(xiàng)目的實(shí)現(xiàn)步驟

    通過(guò)React組件庫(kù)和TypeScript的強(qiáng)類型特性,開發(fā)者可以創(chuàng)建出具有優(yōu)秀用戶體驗(yàn)和穩(wěn)定性的Web應(yīng)用程序,本文主要介紹了React+Typescript創(chuàng)建項(xiàng)目的實(shí)現(xiàn)步驟,感興趣的可以了解一下
    2023-08-08
  • JS中使用react-tooltip插件實(shí)現(xiàn)鼠標(biāo)懸浮顯示框

    JS中使用react-tooltip插件實(shí)現(xiàn)鼠標(biāo)懸浮顯示框

    前段時(shí)間遇到的一個(gè)需求,要求鼠標(biāo)懸停顯示使用描述, 用到了react-tooltip插件,今天寫一個(gè)總結(jié),感興趣的朋友跟隨小編一起看看吧
    2019-05-05
  • 在react中使用vue的狀態(tài)管理的方法示例

    在react中使用vue的狀態(tài)管理的方法示例

    這篇文章主要介紹了在react中使用vue的狀態(tài)管理的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • react腳手架如何配置less和ant按需加載的方法步驟

    react腳手架如何配置less和ant按需加載的方法步驟

    這篇文章主要介紹了react腳手架如何配置less和ant按需加載的方法步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • antd4里table滾動(dòng)的實(shí)現(xiàn)

    antd4里table滾動(dòng)的實(shí)現(xiàn)

    本文主要介紹了antd4里table滾動(dòng)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • react echarts tooltip 區(qū)域新加輸入框編輯保存數(shù)據(jù)功能

    react echarts tooltip 區(qū)域新加輸入框編輯保存數(shù)據(jù)功能

    這篇文章主要介紹了react echarts tooltip 區(qū)域新加輸入框編輯保存數(shù)據(jù)功能,大概思路是用一個(gè)div包裹echarts, 然后在echarts的同級(jí)新建一個(gè)div用來(lái)用來(lái)模擬真實(shí)tooltip,通過(guò)鼠標(biāo)移入移出事件控制真實(shí)tooltip的顯示與隱藏,需要的朋友可以參考下
    2023-05-05
  • React-Native中一些常用組件的用法詳解(一)

    React-Native中一些常用組件的用法詳解(一)

    這篇文章主要跟大家分享了關(guān)于React-Native中一些常用組件的用法,其中包括View組件、Text組件、Touchable類組件、TextInput組件以及Image組件的使用方法,分別給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),需要的朋友們下面來(lái)一起看看吧。
    2017-06-06
  • 在react項(xiàng)目中webpack使用mock數(shù)據(jù)的操作方法

    在react項(xiàng)目中webpack使用mock數(shù)據(jù)的操作方法

    這篇文章主要介紹了在react項(xiàng)目中webpack使用mock數(shù)據(jù)的操作方法,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-06-06

最新評(píng)論