React component re-render

由列表優化談起re-render

why re-render?

這兩天在看項目的渲染優化題,決定總結一下,發現不管是代碼寫法和組件規劃以及列表之間的交互,都是有可能會引發性能問題的罪魁禍首。react

首先分析一下,組件什麼時候更新?爲什麼更新?git

how does React decide to re-render a component

  1. component state changegithub

    舉個栗子:npm

    class Test extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                value: 0
            }
        }
        handleClick = () => {
            this.setState({
                value: this.state.value ++
            })
        }
        render() {
            return (<div onClick={this.handleClick}>{this.state.text}</div>)
        }
    }複製代碼

    可是你們都知道,react的實現思想就是virtual DOM,每次state的改變都會引發re-render,無論state裏的值是否真正用到了組件中,我從一遍博客中看到這樣的描述:A re-render can only be triggered if a component’s state has changed. The state can change from a props change, or from a direct setState change. The component gets the updated state and React decides if it should re-render the component. Unfortunately, by default React is incredibly simplistic and basically re-renders everything all the time.那麼什麼東西適合放在state裏----須要持續維護的一個局部狀態或者跟UI相關的狀態纔去放在state裏,而那些只是暫時性的東西或者特定函數裏纔會用到的,只須要放在組件實例中。最後一句話:state雖靈活,用時需謹慎。redux

  2. component props changebash

    先放栗子:app

    class Mine extends React.Component {
        render() {
            const { childIds } = this.props
            return (
              <FileLis childIds={childIds} />
            )
        }
    }
    ​
    export default connect((state, ownProps) => {
        childIds: selectFileChildIds(state, ownProps.match.params.guid || '0')
    })(Mine)複製代碼

    很簡單,當數據改變的時候必然會re-renderide

  3. react component re-render in these instances函數

    • Parent component re-render工具

    • Calling this.setState() within the component 而且會依次根據react 生命週期更新 shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate

    • component's props changes. 而且依次走生命週期 componentWillReceivePorps -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate(connect method of react-redux trigger this when there are applicable changes in the Redux store)

    • calling this.forceUpdate which is similar to this.setState

Re-render necessary or unnecessarily?

什麼是必須的re-render什麼是沒必要要的re-render,咱們能夠藉助react-devtools,勾選Highlight Updates,


而後click button or do some thing 引發組件的render,這裏有個todo list highlight-demo.firebaseapp.com/你會看到頁面上會出現藍色,綠色, 黃色,紅色。其中藍色是指最不頻繁的更新,其次是綠色,黃色,紅色。黃色和紅色並不必定是很差的,之因此出現黃色或者紅色,組件這個時候確實由於某些state或者props改變致使了頻繁更新。

好比項目中桌面列表的渲染:


只是簡單的修改了某個文件的一個屬性,會看到整個list都重繪了一遍,設置右邊和左邊的側欄以及header都re-render了,這就是沒必要要的re-render

優化列表之後的效果:


能夠看到綠色部分只是修改的file發生了re-render

why did you updated

在優化列表渲染的時候,用到了一個輔助工具--why-did-you-update

既然列表在重複渲染,那就要知道到底哪一個組件哪一個東西引發了重複渲染,其實咱們是有線索能夠查找的,而後藉助why-did-you-update這個工具會幫助咱們在控制檯顯示哪些組件在重複渲染,以及什麼緣由致使的。

Why-did-you-update 是個npm 包,npm install --save why-did-you-update or yarn add --save why-did-update

開發環境下使用它

import Rect from 'react'
if (process.env.NODE_ENV !== 'production') {
    const { whyDidYouUpdate } = require('why-did-you-update')
    whyDIdYouUpdate(React)
}複製代碼

分析結果

減小或者控制沒必要要的re-render

use PureComponent

合理使用props傳遞數據

計算放在connect裏

儘可能不要傳遞state

不要在react component render 裏使用箭頭函數

class Item extends React.Component {
    render() {
        const { mode } = this.props
        return (
            <div onCick={() => this.handleClick(mode)}>...</div>
        )
    }
}複製代碼

👆的作法每次render都會生成一個新的匿名函數,然而其實函數並無變只是引用變了,形成re-render。The problem with using an arrow function in the render call is it will create a new function every time, which ends up causing unneeded re-renders

參考資料

lucybain.com/blog/2017/r…

stackoverflow.com/questions/4…

github.com/maicki/why-…

相關文章
相關標籤/搜索