這兩天在看項目的渲染優化題,決定總結一下,發現不管是代碼寫法和組件規劃以及列表之間的交互,都是有可能會引發性能問題的罪魁禍首。react
首先分析一下,組件什麼時候更新?爲什麼更新?git
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
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
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什麼是沒必要要的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-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)
}複製代碼
分析結果
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