react優(yōu)化性能的幾點

1. 基本原理

1.1 render()函數(shù)

一般來說,要盡可能少地在 render 函數(shù)中做操作。如果非要做一些復雜操作或者計算,也許你可以考慮使用一個 memoized 函數(shù)以便于緩存那些重復的結果??梢钥纯?Lodash.memoize,這是一個開箱即用的記憶函數(shù)。

反過來講,避免在組件的 state 上存儲一些容易計算的值也很重要。舉個例子,如果 props 同時包含 firstName 和 lastName,沒必要在 state 上存一個 fullName,因為它可以很容易通過提供的 props 來獲取。如果一個值可以通過簡單的字符串拼接或基本的算數(shù)運算從 props 派生出來,那么沒理由將這些值包含在組件的 state 上。

1.2 Prop 和 state

重要的是要記住,只要 props(或 state)的值不等于之前的值,React 就會觸發(fā)重新渲染。如果 props 或者 state 包含一個對象或者數(shù)組,嵌套值中的改變會觸發(fā)重新渲染??紤]到這一點,你需要注意在每次渲染的生命周期中,創(chuàng)建一個新的 props 或者 state 都可能無意中導致了性能下降。(注:對象或者數(shù)組只要引用不變,是不會觸發(fā)rerender的)

舉幾個現(xiàn)在我在開發(fā)中遇到的幾個問題:

例子: 函數(shù)綁定的問題

/*
給 prop 傳入一個行內(nèi)綁定的函數(shù)(包括 ES6 箭頭函數(shù))實質(zhì)上是在每次父組件 render 時傳入一個新的函數(shù)。
*/
render() {
  return (
    <div>
      <a onClick={() => this.onRender()}>顯示</a>
      <a onClick={() => this.onRender.bind(this)}>顯示</a>
    </div>
  );
}


/*
應該在構造函數(shù)中處理函數(shù)綁定并且將已經(jīng)綁定好的函數(shù)作為 prop 的值
*/

constructor( props ) {
  this.doSomething = this.doSomething.bind( this );
  //or
  this.doSomething = (...args) => this.doSomething(...args);
}
render() {
  return (
    <div>
       <a onClick={ this.onRender }>顯示</a>
    </div>
  );
}

例子: 對象或數(shù)組字面量

/*
對象或者數(shù)組字面量在功能上來看是調(diào)用了 Object.create() 和 new Array()。這意味如果給 prop 傳遞了對象字面量或者數(shù)組字面量。每次render 時 React 會將他們作為一個新的值。這在處理 行內(nèi)樣式時通常是有問題的。
*/

/*遇到的寫法 */
// 每次渲染時都會為 style 新建一個對象字面量
render() {
  return <div style={ { backgroundColor: 'red' } }/>
}

/* 建議寫法 */
// 在組件外聲明
const style = { backgroundColor: 'red' };

render() {
  return <div style={ style }/>
}

例子 : 注意兜底值字面量

/*
有時我們會在 render 函數(shù)中創(chuàng)建一個兜底的值來避免 undefined 報錯。在這些情況下,最好在組件外創(chuàng)建一個兜底的常量而不是創(chuàng)建一個新的字面量。
/*
/* 遇到的寫法 */
render() {
  let thingys = [];
  // 如果 this.props.thingys 沒有被定義,一個新的數(shù)組字面量會被創(chuàng)建
  if( this.props.thingys ) {
    thingys = this.props.thingys;
  }

  return <ThingyHandler thingys={ thingys }/>
}

/* 遇到的寫法 */
render() {
  // 這在功能上和前一個例子一樣
  return <ThingyHandler thingys={ this.props.thingys || [] }/>
}

/* 建議的寫法*/

// 在組件外部聲明
const NO_THINGYS = [];

render() {
  return <ThingyHandler thingys={ this.props.thingys || NO_THINGYS }/>
}

1.3 盡可能的保持 Props(和 State)簡單和精簡

理想情況下,傳遞給組件的 props 應該是它直接需要的。為了將值傳給子組件而將一個大的、復雜的對象或者很多獨立的 props 傳遞給一個組件會導致很多不必要的組件渲染(并且會增加開發(fā)復雜性)。

我們使用 Redux 作為狀態(tài)容器,所以在我們看來,最理想的是方案在組件層次結構的每一個層級中使用 react-reduxconnect() 函數(shù)直接從 store 上獲取數(shù)據(jù)。connect 函數(shù)的性能很好,并且使用它的開銷也非常小。

這里已經(jīng)優(yōu)化了。

1.4 組件方法

由于組件方法是為組件的每個實例創(chuàng)建的,如果可能的話,使用 helper/util 模塊的純函數(shù)或者靜態(tài)類方法。尤其在渲染大量組件的應用中會有明顯的區(qū)別。

2. 組件是否重新渲染

視圖的變化是邪惡的

2.1 shouldComponentUpdate()

React 有一個生命周期函數(shù) shouldComponentUpdate()。這個方法可以根據(jù)當前的和下一次的 props 和 state 來通知這個 React 組件是否應該被重新渲染。

然而使用這個方法有一個問題,開發(fā)者必須考慮到需要觸發(fā)重新渲染的每一種情況。這會導致邏輯復雜,一般來說,會非常痛苦。如果非常需要,你可以使用一個自定義的shouldComponentUpdate()
方法,但是很多情況下有更好的選擇。

2.2 React.PureComponent

React 從 v15 開始會包含一個 PureComponent 類,它可以被用來構建組件。React.PureComponent聲明了它自己的 shouldComponentUpdate() 方法,它自動對當前的和下一次的 props 和 state 做一次淺對比。有關淺對比的更多信息,請參考這個 Stack Overflow:http://stackoverflow.com/questions/36084515/how-does-shallow-compare-work-in-react

在大多數(shù)情況下,React.PureComponent 是比 React.Component更好的選擇。在創(chuàng)建新組件時,首先嘗試將其構建為純組件,只有組件的功能需要時才使用 React.Component。更多信息,請查閱相關文檔 React.PureComponent。

2.3 怎么使用PureComponent

PureComponent節(jié)約了我們的時間,避免了多余的代碼。那么,掌握如何正確使用它是非常重要的,否則如果使用不當,它就無法發(fā)揮作用。因為PureComponent僅僅是淺比較(shadow comparison),所以改變組件內(nèi)部的 props 或者 state ,它將不會發(fā)揮作用。所以建議按上面建議的幾種寫法來開發(fā)。這樣如果用上面建議的寫法來寫的話就有兩個好處:

  • 一是避免組件每次渲染都做重復的事
  • 二是避免在使用PureComponent時損失PureComponent的優(yōu)點

注意:
使用了pureComponent之后,只是淺比較,這樣會導致改變組件內(nèi)部的props之后不會更新視圖,所以pureComponent建議用在純UI類的組件里。

正常情況下,遷移的方式非常簡單,就像改變組件繼承的基類,從

class MyComponent extends Component {...}

class MyComponent extends PureComponent {...}

在PureComponent出現(xiàn)之前,通常是自己實現(xiàn)一個這樣的組件:

import React,{ Component }from 'react'
import shallowEqual from 'react-pure-render/shallowEqual'

export default class PureComponent extends Component{
  shouldComponentUpdate(nextProps, nextState) {
    return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState)
  }
}

當然react性能優(yōu)化不僅僅有上面提到的幾點,還可以從webpack,使用immutable.js上優(yōu)化

tuiguang.png
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 作為一個合格的開發(fā)者,不要只滿足于編寫了可以運行的代碼。而要了解代碼背后的工作原理;不要只滿足于自己的程序...
    六個周閱讀 8,664評論 1 33
  • 說在前面 關于 react 的總結過去半年就一直碎碎念著要搞起來,各(wo)種(tai)原(lan)因(le)。心...
    陳嘻嘻啊閱讀 7,018評論 7 41
  • 3. JSX JSX是對JavaScript語言的一個擴展語法, 用于生產(chǎn)React“元素”,建議在描述UI的時候...
    pixels閱讀 2,971評論 0 24
  • 深入JSX date:20170412筆記原文其實JSX是React.createElement(componen...
    gaoer1938閱讀 8,175評論 2 35
  • 40、React 什么是React?React 是一個用于構建用戶界面的框架(采用的是MVC模式):集中處理VIE...
    萌妹撒閱讀 1,179評論 0 1

友情鏈接更多精彩內(nèi)容