最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談react性能優(yōu)化的方法

 更新時(shí)間:2018年09月05日 10:40:19   作者:havywu  
這篇文章主要介紹了淺談react性能優(yōu)化的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

React性能優(yōu)化思路

軟件的性能優(yōu)化思路就像生活中去看病,大致是這樣的:

使用工具來分析性能瓶頸(找病根)

嘗試使用優(yōu)化技巧解決這些問題(服藥)

使用工具測(cè)試性能是否確實(shí)有提升(療效確認(rèn))

初識(shí)react只是為了盡快完成項(xiàng)目,后期進(jìn)行代碼審查時(shí)候發(fā)現(xiàn)有很多地方需要優(yōu)化,因此做了個(gè)小結(jié)。

  • Code Splitting
  • shouldComponentUpdate避免重復(fù)渲染
  • 使用不可突變數(shù)據(jù)結(jié)構(gòu)
  • 組件盡可能的進(jìn)行拆分、解耦
  • 列表類組件優(yōu)化
  • bind函數(shù)優(yōu)化
  • 不要濫用props
  • ReactDOMServer進(jìn)行服務(wù)端渲染組件

Code Splitting

Code Splitting 可以幫你“懶加載”代碼,如果你沒辦法直接減少應(yīng)用的體積,那么不妨嘗試把應(yīng)用從單個(gè) bundle 拆分成單個(gè) bundle + 多份動(dòng)態(tài)代碼的形式。

webpack提供三種代碼分離方法,詳情見webpack官網(wǎng)

  • 入口起點(diǎn):使用 entry 配置手動(dòng)地分離代碼。
  • 防止重復(fù):使用 SplitChunks 去重和分離 chunk。
  • 動(dòng)態(tài)導(dǎo)入:通過模塊的內(nèi)聯(lián)函數(shù)調(diào)用來分離代碼。

在此,主要了解一下第三種動(dòng)態(tài)導(dǎo)入的方法。

1、例如可以把下面的import方式

import { add } from './math';
console.log(add(16, 26));

改寫成動(dòng)態(tài) import 的形式,讓首次加載時(shí)不去加載 math 模塊,從而減少首次加載資源的體積。

import("./math").then(math => {
 console.log(math.add(16, 26));
});

2、例如引用react的高階組件react-loadable進(jìn)行動(dòng)態(tài)import。

import Loadable from 'react-loadable';
import Loading from './loading-component';

const LoadableComponent = Loadable({
 loader: () => import('./my-component'),
 loading: Loading,
});

export default class App extends React.Component {
 render() {
  return <LoadableComponent/>;
 }
}

上面的代碼在首次加載時(shí),會(huì)先展示一個(gè) loading-component,然后動(dòng)態(tài)加載 my-component 的代碼,組件代碼加載完畢之后,便會(huì)替換掉 loading-component

shouldComponentUpdate避免重復(fù)渲染

當(dāng)一個(gè)組件的props或者state改變時(shí),React通過比較新返回的元素和之前渲染的元素來決定是否有必要更新實(shí)際的DOM。當(dāng)他們不相等時(shí),React會(huì)更新DOM。

在一些情況下,你的組件可以通過重寫這個(gè)生命周期函數(shù)shouldComponentUpdate來提升速度, 它是在重新渲染過程開始前觸發(fā)的。 這個(gè)函數(shù)默認(rèn)返回true,可使React執(zhí)行更新。

為了進(jìn)一步說明問題,引用官網(wǎng)的圖解釋一下,如下圖( SCU表示shouldComponentUpdate,綠色表示返回true(需要更新),紅色表示返回false(不需要更新);vDOMEq表示虛擬DOM比對(duì),綠色表示一致(不需要更新),紅色表示發(fā)生改變(需要更新)):

根據(jù)渲染流程,首先會(huì)判斷shouldComponentUpdate(SCU)是否需要更新。如果需要更新,則調(diào)用組件的render生成新的虛擬DOM,然后再與舊的虛擬DOM對(duì)比(vDOMEq),如果對(duì)比一致就不更新,如果對(duì)比不同,則根據(jù)最小粒度改變?nèi)ジ翫OM;如果SCU不需要更新,則直接保持不變,同時(shí)其子元素也保持不變。

  • C1根節(jié)點(diǎn),綠色SCU、紅色vDOMEq,表示需要更新。
  • C2節(jié)點(diǎn),紅色SCU,表示不需要更新,同時(shí)
  • C4、C5作為其子節(jié)點(diǎn)也不需要檢查更新。
  • C3節(jié)點(diǎn),綠色SCU、紅色vDOMEq,表示需要更新。
  • C6節(jié)點(diǎn),綠色SCU、紅色vDOMEq,表示需要更新。
  • C7節(jié)點(diǎn),紅色SCU,表示不需要更新。
  • C8節(jié)點(diǎn),綠色SCU,表示React需要渲染這個(gè)組件;綠色vDOMEq,表示虛擬DOM一致,不更新DOM。

因此,我們可以通過根據(jù)自己的業(yè)務(wù)特性,重載shouldComponentUpdate,只在確認(rèn)真實(shí)DOM需要改變時(shí),再返回true。一般的做法是比較組件的props和state是否真的發(fā)生變化,如果發(fā)生變化則返回true,否則返回false。引用官網(wǎng)的案例。

class CounterButton extends React.Component {
 constructor(props) {
  super(props);
  this.state = {count: 1};
 }

 shouldComponentUpdate(nextProps, nextState) {
  if (this.props.color !== nextProps.color) {
   return true;
  }
  if (this.state.count !== nextState.count) {
   return true;
  }
  return false;
 }

 render() {
  return (
   <button
    color={this.props.color}
    onClick={() => this.setState(state => ({count: state.count + 1}))}>
    Count: {this.state.count}
   </button>
  );
 }
}

在以上代碼中,shouldComponentUpdate只檢查props.color和state.count的變化。如果這些值沒有變化,組件就不會(huì)更新。當(dāng)你的組件變得更加復(fù)雜時(shí),你可以使用類似的模式來做一個(gè)“淺比較”,用來比較屬性和值以判定是否需要更新組件。這種模式十分常見,因此React提供了一個(gè)輔助對(duì)象來實(shí)現(xiàn)這個(gè)邏輯 - 繼承自React.PureComponent。

大部分情況下,你可以使用React.PureComponent而不必寫你自己的shouldComponentUpdate,它只做一個(gè)淺比較。但是當(dāng)你比較的目標(biāo)為引用類型數(shù)據(jù),淺比較會(huì)忽略屬性或狀態(tài)突變的情況,此時(shí)你不能使用它,此時(shí)你需要關(guān)注下面的不可突變數(shù)據(jù)。

附:數(shù)據(jù)突變(mutated)是指變量的引用沒有改變(指針地址未改變),但是引用指向的數(shù)據(jù)發(fā)生了變化(指針指向的數(shù)據(jù)發(fā)生變更)。例如const x = {foo:'foo'}。x.foo='none' 就是一個(gè)突變。

使用不可突變數(shù)據(jù)結(jié)構(gòu)

引用官網(wǎng)中的例子解釋一下突變數(shù)據(jù)產(chǎn)生的問題。例如,假設(shè)你想要一個(gè)ListOfWords組件來渲染一個(gè)逗號(hào)分隔的單詞列表,并使用一個(gè)帶了點(diǎn)擊按鈕名字叫WordAdder的父組件來給子列表添加一個(gè)單詞。以下代碼并不正確:

class ListOfWords extends React.PureComponent {
 render() {
  return <div>{this.props.words.join(',')}</div>;
 }
}

class WordAdder extends React.Component {
 constructor(props) {
  super(props);
  this.state = {
   words: ['marklar']
  };
  this.handleClick = this.handleClick.bind(this);
 }

 handleClick() {
  // 這段內(nèi)容將會(huì)導(dǎo)致代碼不會(huì)按照你預(yù)期的結(jié)果運(yùn)行
  const words = this.state.words;
  words.push('marklar');
  this.setState({words: words});
 }

 render() {
  return (
   <div>
    <button onClick={this.handleClick} />
    <ListOfWords words={this.state.words} />
   </div>
  );
 }
}

導(dǎo)致代碼無法正常工作的原因是 PureComponent 僅僅對(duì) this.props.words的新舊值進(jìn)行“淺比較”。在words值在handleClick中被修改之后,即使有新的單詞被添加到數(shù)組中,但是this.props.words的新舊值在進(jìn)行比較時(shí)是一樣的(引用對(duì)象比較),因此 ListOfWords 一直不會(huì)發(fā)生渲染。
避免此類問題最簡(jiǎn)單的方式是避免使用值可能會(huì)突變的屬性或狀態(tài),如:

1、數(shù)組使用concat,對(duì)象使用Object.assign()

handleClick() {
 this.setState(prevState => ({
  words: prevState.words.concat(['marklar'])
 }));
}
// 假設(shè)我們有一個(gè)叫colormap的對(duì)象,下面方法不污染原始對(duì)象
function updateColorMap(colormap) {
 return Object.assign({}, colormap, {right: 'blue'});
}

2、ES6支持?jǐn)?shù)組或?qū)ο蟮膕pread語法

handleClick() {
 this.setState(prevState => ({
  words: [...prevState.words, 'marklar'],
 }));
};
function updateColorMap(colormap) {
 return {...colormap, right: 'blue'};
}

3、使用不可突變數(shù)據(jù)immutable.js

immutable.js使得變化跟蹤很方便。每個(gè)變化都會(huì)導(dǎo)致產(chǎn)生一個(gè)新的對(duì)象,因此我們只需檢查索引對(duì)象是否改變。

const SomeRecord = Immutable.Record({ foo: null });
const x = new SomeRecord({ foo: 'bar' });
const y = x.set('foo', 'baz');
x === y; // false

在這個(gè)例子中,x突變后返回了一個(gè)新的索引,因此我們可以安全的確認(rèn)x被改變了。

不可突變的數(shù)據(jù)結(jié)構(gòu)幫助我們輕松的追蹤對(duì)象變化,從而可以快速的實(shí)現(xiàn)shouldComponentUpdate。

具體如何使用可參考下面文章:Immutable 詳解及 React 中實(shí)踐

組件盡可能的進(jìn)行拆分、解耦

組件盡可能的細(xì)分,比如一個(gè)input+list組件,可以將list分成一個(gè)PureComponent,只在list數(shù)據(jù)變化時(shí)更新。否則在input值變化頁面重新渲染的時(shí)候,list也需要進(jìn)行不必要的DOM diff。

列表類組件優(yōu)化

key屬性在組件類之外提供了另一種方式的組件標(biāo)識(shí)。通過key標(biāo)識(shí),在組件發(fā)生增刪改、排序等操作時(shí),可以根據(jù)key值的位置直接調(diào)整DOM順序,告訴React 避免不必要的渲染而避免性能的浪費(fèi)。
例,對(duì)于一個(gè)基于排序的組件渲染:

var items = sortBy(this.state.sortingAlgorithm, this.props.items);
return items.map(function(item){
 return <img src={item.src} />
});

當(dāng)順序發(fā)生改變時(shí),React 會(huì)對(duì)元素進(jìn)行diff操作,并改img的src屬性。顯示,這樣的操作效率是非常低的。這時(shí),我們可以為組件添加一個(gè)key屬性以唯一的標(biāo)識(shí)組件:

return <img src={item.src} key={item.id} />

增加key后,React就不是diff,而是直接使用insertBefore操作移動(dòng)組件位置,而這個(gè)操作是移動(dòng)DOM節(jié)點(diǎn)最高效的辦法。

bind函數(shù)

綁定this的方式:一般有下面3種方式:

1、constructor綁定

constructor(props) {
  super(props);
  this.handleClick = this.handleClick.bind(this); //構(gòu)造函數(shù)中綁定
}
//然后可以
<p onClick={this.handleClick}>

2、使用時(shí)綁定

<p onClick={this.handleClick.bind(this)}>

3、使用箭頭函數(shù)

<Test click={() => { this.handleClick() }}/>

以上三種方法,第一種最優(yōu)。

因?yàn)榈谝环N構(gòu)造函數(shù)只在組件初始化的時(shí)候執(zhí)行一次,

第二種組件每次render都會(huì)執(zhí)行

第三種在每一次render時(shí)候都會(huì)生成新的箭頭函數(shù)。例:Test組件的click屬性是個(gè)箭頭函數(shù),組件重新渲染的時(shí)候Test組件就會(huì)

因?yàn)檫@個(gè)新生成的箭頭函數(shù)而進(jìn)行更新,從而產(chǎn)生Test組件的不必要渲染。

不要濫用props

props盡量只傳需要的數(shù)據(jù),避免多余的更新,盡量避免使用{...props}

ReactDOMServer進(jìn)行服務(wù)端渲染組件

為了用戶會(huì)更快速地看到完整渲染的頁面,可以采用服務(wù)端渲染技術(shù),在此了解一下ReactDOMServer。

為了實(shí)現(xiàn)SSR,你可能會(huì)用nodejs框架(Express、Hapi、Koa)來啟動(dòng)一個(gè)web服務(wù)器,接著調(diào)用 renderToString 方法去渲染你的根組件成為字符串,最后你再輸出到 response。

// using Express
import { renderToString } from "react-dom/server";
import MyPage from "./MyPage";
app.get("/", (req, res) => {
 res.write("<!DOCTYPE html><html><head><title>My Page</title></head><body>");
 res.write("<div id='content'>"); 
 res.write(renderToString(<MyPage/>));
 res.write("</div></body></html>");
 res.end();
});

客戶端使用render方法來生成HTML

import ReactDOM from 'react-dom';
import MyPage from "./MyPage";
ReactDOM.render(<MyPage />, document.getElementById('app'));

react性能檢測(cè)工具

react16版本之前,我們可以使用react-addons-perf工具來查看,而在最新的16版本,我們只需要在url后加上?react_pref。
首先來了解一下react-addons-perf

react-addons-perf這是 React 官方推出的一個(gè)性能工具包,可以打印出組件渲染的時(shí)間、次數(shù)、浪費(fèi)時(shí)間等。
簡(jiǎn)單說幾個(gè)api,具體用法可參考官網(wǎng)

  • Perf.start() 開始記錄
  • Perf.stop() 結(jié)束記錄
  • Perf.printInclusive() 查看所有設(shè)計(jì)到的組件render
  • Perf.printWasted() 查看不需要的浪費(fèi)組件render

再來了解一下,react16版本的方法,在url后加上?react_pref,就可以在chrome瀏覽器的performance,我們可以查看User Timeing來查看組件的加載時(shí)間。點(diǎn)擊record開始記錄,注意記錄時(shí)長(zhǎng)不要超過20s,否則可能導(dǎo)致chrome掛起。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • React中實(shí)現(xiàn)keepalive組件緩存效果的方法詳解

    React中實(shí)現(xiàn)keepalive組件緩存效果的方法詳解

    由于react官方并沒有提供緩存組件相關(guān)的api(類似vue中的keepalive),在某些場(chǎng)景,會(huì)使得頁面交互性變的很差。所以本文為大家介紹了React中實(shí)現(xiàn)keepalive組件緩存效果的方法,希望對(duì)大家有所幫助
    2023-01-01
  • React?diff算法超詳細(xì)講解

    React?diff算法超詳細(xì)講解

    渲染真實(shí)DOM的開銷很大,有時(shí)候我們修改了某個(gè)數(shù)據(jù),直接渲染到真實(shí)dom上會(huì)引起整個(gè)dom樹的重繪和重排。我們希望只更新我們修改的那一小塊dom,而不是整個(gè)dom,diff算法就幫我們實(shí)現(xiàn)了這點(diǎn)。diff算法的本質(zhì)就是:找出兩個(gè)對(duì)象之間的差異,目的是盡可能做到節(jié)點(diǎn)復(fù)用
    2022-11-11
  • useEffect中return函數(shù)的作用和執(zhí)行時(shí)機(jī)解讀

    useEffect中return函數(shù)的作用和執(zhí)行時(shí)機(jī)解讀

    這篇文章主要介紹了useEffect中return函數(shù)的作用和執(zhí)行時(shí)機(jī),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • React實(shí)現(xiàn)錨點(diǎn)跳轉(zhuǎn)組件附帶吸頂效果的示例代碼

    React實(shí)現(xiàn)錨點(diǎn)跳轉(zhuǎn)組件附帶吸頂效果的示例代碼

    這篇文章主要為大家詳細(xì)介紹了React如何實(shí)現(xiàn)移動(dòng)端錨點(diǎn)跳轉(zhuǎn)組件附帶吸頂效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
    2023-01-01
  • React狀態(tài)管理器Rematch的使用詳解

    React狀態(tài)管理器Rematch的使用詳解

    rematch是對(duì)redux的二次封裝,簡(jiǎn)化了redux是使用,極大的提高了開發(fā)體驗(yàn),這篇文章主要介紹了React狀態(tài)管理器Rematch的使用,需要的朋友可以參考下
    2022-09-09
  • React可定制黑暗模式切換開關(guān)組件

    React可定制黑暗模式切換開關(guān)組件

    這篇文章主要為大家介紹了React可定制黑暗模式切換開關(guān)組件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • react+antd4實(shí)現(xiàn)優(yōu)化大批量接口請(qǐng)求

    react+antd4實(shí)現(xiàn)優(yōu)化大批量接口請(qǐng)求

    這篇文章主要為大家詳細(xì)介紹了如何使用react hooks + antd4實(shí)現(xiàn)大批量接口請(qǐng)求的前端優(yōu)化,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下
    2024-02-02
  • react使用mobx封裝管理用戶登錄的store示例詳解

    react使用mobx封裝管理用戶登錄的store示例詳解

    這篇文章主要介紹了react基于mobx封裝管理用戶登錄的store,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • React官方團(tuán)隊(duì)完善原生Hook閉包陷阱

    React官方團(tuán)隊(duì)完善原生Hook閉包陷阱

    這篇文章主要為大家介紹了React官方團(tuán)隊(duì)出手,補(bǔ)齊原生Hook短板閉包陷阱的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • 基于react后端渲染模板引擎noox發(fā)布使用

    基于react后端渲染模板引擎noox發(fā)布使用

    本篇文章主要介紹了基于react后端渲染模板引擎noox發(fā)布使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01

最新評(píng)論

昌乐县| 洛扎县| 舞钢市| 垦利县| 鄯善县| 屏山县| 洛隆县| 铁岭市| 宝丰县| 辽阳县| 拜城县| 房产| 吴忠市| 怀仁县| 贵德县| 卓资县| 阿克陶县| 东台市| 泰和县| 大港区| 大埔区| 云梦县| 兴城市| 东乌| 拜城县| 固始县| 新干县| 桃园市| 江西省| 双鸭山市| 东乌| 柘荣县| 鹿泉市| 金华市| 安龙县| 乡宁县| 邵武市| 通渭县| 万年县| 武强县| 依兰县|