原文連接:https://ssshooter.com/2019-03...javascript
我曾經對 shouldComponentUpdate 的用途不解。react 的賣點之一,是經過 diff 虛擬節點樹,減小對真實節點的操做,因此我之前覺得既然 diff 了,那就天然知道節點有沒有更新了,diff 是根據 setState 的內容進行的,那 shouldComponentUpdate 有什麼用呢?html
然而我之前的理解是徹底錯誤的,形成這個疑問的緣由即是對 React 渲染流程的不熟悉。從頭提及。java
你修改了數據,須要 React 從新渲染頁面,讓你的新數據展現在頁面上,須要藉助 setState
方法。react
setState
調用後,組件的 render
方法也會自動調用,這就是爲何你能在頁面看到新數據。可是不管你 setState
修改的是什麼,哪怕是頁面裏沒有的一個數據,render
都會被觸發,而且父組件渲染中會嵌套渲染自組件。git
class Nest extends React.Component { render() { console.log('inner') return <div>Nest</div> } } class App extends React.Component { render() { console.log('outer') return ( <div> <button onClick={() => { this.setState({ anything: 1, }) }} > setState </button> <Nest /> </div> ) } }
因此在這個例子中,點擊按鈕,即便修改的 anything 根本沒有出現,甚至沒有定義,render 函數仍是如期運行。每次點擊按鈕,上面的代碼會先輸出 outer,而後輸出 inner。github
render 生成的是什麼呢?通常來講你們都是寫 jsx,因此視覺上是一個「dom」,可是實際上,官網也在顯眼的位置告訴你,這實際上是一個函數。算法
// jsx const element = <h1 className="greeting">Hello, world!</h1> // babel 轉換爲瀏覽器能運行的函數 const element = React.createElement( 'h1', { className: 'greeting' }, 'Hello, world!' )
而由於 React 的組件層層嵌套,render 函數會生成一棵描述應用結構的節點樹,並保存在內存中。在下一次渲染時,新的樹會被生成,接着就是對比兩棵樹。瀏覽器
官方一點的定義應該稱爲 reconciliation,也就是 React 用來比較兩棵節點樹的算法,它肯定樹中的哪些部分須要被更新。babel
在肯定兩棵樹的區別後,會根據不一樣的地方對實際節點進行操做,這樣你看到的界面終於在這一步獲得了改變。當年 React 也就由於這個高效的 dom 操做方法獲得追捧。dom
終於說到 shouldComponentUpdate
,他是一個組件的方法,用於攔截組件渲染。讓咱們用例子解釋所謂「攔截渲染」。
class Nest extends React.Component { shouldComponentUpdate = () => { // <---- 注意這裏 return false } render() { console.log('inner') return <div>Nest</div> } } class App extends React.Component { render() { console.log('outer') return ( <div> <button onClick={() => { this.setState({ anything: 1, }) }} > setState </button> <Nest /> </div> ) } }
跟以前的例子差很少,不過當咱們在子組件添加 shouldComponentUpdate
後,再點擊按鈕,結果是 ————
沒錯,子組件的渲染函數並無調用,藉助 shouldComponentUpdate
返回 false
,成功攔截了子組件的渲染。
固然通常不會這麼作,由於永遠返回 false 的話這個組件(固然由於渲染函數沒有運行,因此包括其全部子組件都是不會更新的)就永遠不會更新了。
經常使用操做是,在 shouldComponentUpdate
斷定該組件的 props 和 state 是否有變化,就像這樣:
class Nest extends React.Component { shouldComponentUpdate = (nextProps, nextState) => { return ( !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState) ) } render() { console.log('inner') return <div>Nest</div> } }
這樣能夠淺比較 props 和 state 是否有變化,至於爲何不深比較?由於那樣效率可能會比直接全都運行 render 還低...
由於上面的操做太常見,React 直接爲咱們提供了 PureComponent:
class Nest extends React.PureComponent { render() { console.log('inner') return <div>Nest</div> } }
使用 PureComponent 的效果就與上面淺比較同樣,而且省掉了 shouldComponentUpdate。
PureComponent 能提升性能!因此直接用 PureComponent 代替全部 Component!
這固然是錯的。
對於明知道不須要修改的組件,確定直接返回 false。而可能你沒想到,對於明知道須要修改的組件,也請不要使用 PureComponent。
由於正如上面所說,PureComponent 須要進行兩次淺比較,而淺比較也是要時間的,如果你明知道這個組件百分百要修改,何須浪費時間去對比呢?
因此 PureComponent 請用在較少進行修改的組件上。
總結一下以上內容,整個流程基本以下:
本文部分存在我的理解,若是文中有不嚴謹的地方,請在評論區指出,謝謝你們的閱讀。
參考文獻:
https://reactjs.org/docs/faq-...
https://reactjs.org/docs/opti...