vue生命周期和react生命周期總結對比


vue框架和react框架雖然都是虛擬dom,組件化開發,其中的不同點還是蠻多的。首先vue的雙向綁定而react則是單項數據流。react使用了jsx語法,讓編程更組件話。除了這些他們的生命周期還是不一樣的

總歸他們都經歷了 初始化階段,運行階段,銷毀階段。其中運行階段又分渲染和數據更新兩部分

先說下vue的生命周期相對比較簡單:

初始化階段:

1:new Vue(...) : 實例化、組件通過new Vue() 創建出來之后會初始化事件和生命周期,然后就會執行beforeCreate鈎子函數,這個時候,數據還沒有掛載呢,只是一個空殼,無法訪問到數據和真實的dom,一般不做操作

2:beforeCreate,created :掛載數據,綁定事件等等,然后執行created函數,這個時候已經可以使用到數據,也可以更改數據,在這里更改數據不會觸發updated函數,在這里可以在渲染前倒數第二次更改數據的機會,不會觸發其他的鈎子函數,一般可以在這里做初始數據的獲取

運行階段:

1:beforemounted:接下來開始找實例或者組件對應的模板,編譯模板為虛擬dom放入到render函數中准備渲染,然后執行beforeMount鈎子函數,在這個函數中虛擬dom已經創建完成,馬上就要渲染,在這里也可以更改數據,不會觸發updated,在這里可以在渲染前最后一次更改數據的機會,不會觸發其他的鈎子函數,一般可以在這里做初始數據的獲取

2:render ,mounted,beforeupdate,update : 接下來開始render,渲染出真實dom,然后執行mounted鈎子函數,此時,組件已經出現在頁面中,數據、真實dom都已經處理好了,事件都已經掛載好了,可以在這里操作真實dom。

到這里還不算結束,如果在程序運行中,沒有更新數據則無視,一旦有數據更新了,就會走以下兩個鈎子:beforeupdate,update

當組件或實例的數據更改之后,會立即執行beforeUpdate,然后vue的虛擬dom機制會重新構建虛擬dom與上一次的虛擬dom樹利用diff算法進行對比之后重新渲染,當更新完成后,執行updated,數據已經更改完成,dom也重新render完成,可以操作更新后的虛擬dom

銷毀階段:

1:beforeDestroy:當經過某種途徑調用$destroy方法后,立即執行beforeDestroy,一般在這里做一些善后工作,例如清除計時器、清除非指令綁定的事件等等

2:destroyed:組件的數據綁定、監聽...去掉后只剩下dom空殼,這個時候,執行destroyed,在這里做善后工作也可以

總結起來無外乎就七個當然真實的流程要更細致復雜,有興趣的可以自己研究源碼,實際項目中用到這些完全夠了:

newVue()實例化 => beforeCreate,created =>beforemounted,mounted =>(if data change){ beforeupdate,update } => beforedestroyed,destroyed

這里有幾點要注意:

1:Vue的編譯實際上是指Vue把模板編譯成 render 函數的過程

2:render選項參數比template更接近Vue解析器!所以綜合排列如下:

  render函數選項  > template參數  > 外部HTML
3:通過Vue.compile這個實時編譯模板的函數來看一看:
用官方文檔的例子
<div>
  <header>
    <h1>I'm a template!</h1>
  </header>
  <p v-if="message">
    {{ message }}
  </p>
  <p v-else>
    No message.
  </p>
</div>
會被渲染成:
function anonymous() {
  with(this){return _c('div',[_m(0),(message)?_c('p',[_v(_s(message))]):_c('p',[_v("No message.")])])}
}

4:在Vue中,數據更改會導致虛擬 DOM 重新渲染,並先后調用beforeUpdate鈎子函數和updated鈎子函數

重渲染(調用這兩個鈎子函數)的前提是被更改的數據已經被寫入模板中!!(這點很重要)

var vm = new Vue({
  el: '#app',
  data: {
    number: 1
  },
  template: '<div id="app"><p></p></div>',
  beforeUpdate: function () {
    console.log('調用了beforeUpdate鈎子函數')//控制台沒有打印
  },
  updated: function () {
    console.log('調用了updated鈎子函數')//控制台沒有打印
  }
})
 
vm.number = 2
// 在模板中使用number這個數據
  template: '<div id="app"><p>  {{ number }} </p></div>',//添加{{number}}

beforeUpdate: function () {
    console.log('調用了beforeUpdate鈎子函數')//此時被打印出來了
  },
  updated: function () {
    console.log('調用了updated鈎子函數')//此時被打印出來了
  }

也就是說:只有Vue實例中的數據被“寫入”到我們的模板中,它的改變才可以被Vue追蹤,重渲染從而調用 beforeUpdate鈎子函數和updated鈎子函數

5:

beforeDestroy鈎子函數在實例銷毀之前調用。在這一步,實例仍然完全可用。
 
destroyed鈎子函數在Vue 實例銷毀后調用。調用后,Vue 實例指示的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷毀。
 
就如同調用在Vue實例上調用$mounted會使暫停的生命周期繼續一樣,調用$destroy()會直接銷毀實例
 
接下來看react生命周期,它相對於vue生命周期流程差不多但相對復雜點:
 初始化階段:
1:首先是創建構造函數constructor 類似vue實例化new vue()
執行時間:組件被加載前最先調用,並且僅調用一次。作用:定義狀態機變量 
constructor(props) {
    super(props);//如果有父元素繼承父元素的props
    this.state = {
      content:null,
    }
}

執行階段:

1:componentWillMount():這個函數是在render前執行一次,如果在這個函數中調用setState改變某些狀態機,react會等待setState完成后再渲染組件

需要注意的是:如果有子組件,子組件也有此鈎子函數,並且會等待父級的函數調用完成后才會調用子組件的componentWillMount

 2:render():主要用來渲染掛載組件。也是組件的最核心函數,和其它鈎子函數不一樣(上一個鈎子只執行一次)render函數是比較頻繁被調用的:(1)初始化加載頁面(2)狀態機改變setState ( 3 ) 接收到新的props(父組件更新)

需要注意的是render鈎子內不要改變狀態機state

3:componentDidMount():render之后就會調用,它也和componentWillMount一樣只調用一次。它的主要作用就是渲染掛組件可以使用refs了。(如果需要操作dom時)

需要注意的是子組件也有componentDidMount,不過和willMount不同的是子組件會在父組件調用前調用didMount

如果在該函數內修改state,render就會被再次調用。

如果不想多次渲染render,可以選擇將setState放在willMount內。

它比較適合數據初始化后,再異步的請求后端接口或其它數據需要再次更新頁面響應式的時候,請求的接口可以直接放在這里

數據更新監測階段:(如果有數據改變的話):

1:componetWillReceiveProps():上面的是第一遍流程,當后期有新的props傳入,react會調用willReceiveProps鈎子,換句話說,父組件內state值改變了,就會重新渲染render,父組件一render,子組件的props就更新了,也就調用了此鈎子

它的作用和didMount相似,也可以渲染掛在組件使用refs

需要注意的是:react初次渲染時,該函數並不會被觸發,因此有時該函數需要和componentWillMount或componentDidMount組合使用;

使用該函數一定要加nextProps參數:componentWillReceiveProps(nextProps),首次使用了解的可以先打印結果(console.log(nextProps))

2:shouldComponentUpdate() : 每次執行setstate都會執行該函數,也就是說只要一改變狀態,接收到新的state或props 就會調用此更新機制:它有默認的返回值 true,有兩個參數:新的props,新的state:sholdComponentUpdate(nextprops,nextstate)

它的作用是:如果有些變化不需要重新render組件,可以在該函數中阻攔。

注意:該方法在初始化渲染的時候不會調用,在使用 forceUpdate 方法的時候也不會

3:componentWillUpdate():每次執行setstate后,如果setState跟新改變了props,state也就是說通過setstate改變為新的prop,state值,它就會被調用,注意是在重新render前,所以它作用也是在獲取新的prop,state后,為下次render做准備工作

注意:不能再該函數中通過this.setstate再次改變狀態機,如果需要,則在componentWillReceiveProps函數中改變

4:componentDidUpdate():重新渲染后調用,在初始化渲染的時候該方法不會被調用

作用:使用該方法可以在組件更新之后如果還想操作DOM 元素的話可以在此寫入操作

最后是銷毀階段,這里只有一個componentWillUnmount()

 在該方法中執行任何必要的清理,比如無效的定時器,或者清除在 componentDidMount 中創建的 DOM 元素。

 需要注意的是:

1:當一個頁面中存在子父組件時,要注意componentWillMount和componentDidMount的使用,如果需要先加載父組件(獲取網路數據),父組件傳值給子組件,再加載子組件(獲取網路數據),那么不能同時在子父組件中使用componentDidMount獲取網路數據,因為會先執行子組件的componentDidMount,會由於未得到父組件的傳值而報錯;解決方案:(1)父組件:componentWillMount,子組件:componentDidMount;(2)父組件:componentDidMount,子組件:componentWillMount;
他們的真確順序應該是:父componentWillMount => 子componentDidMount=>父componentDidMount=>子componentWillMount

2:當一個頁面中如要實現兩個組件的聯動效果,(比如:頁面中包含componentA和componentB,單擊componentA,componentB內容對應變化,componentA向componentB通過redux傳參,那么componentB首次會通過componentDidMount接收,然后再通過componentWillReceiveProps接收)

需要額外注意的是:react17版本以后:有些生命周期基本棄用了(過時):不建議使用因為強制使用它們還是會有效

1:componentWillMount():建議在constructor()內初始化state,如果是訂閱類建議在componentDidMount()內進行

2:componentWillReceiveProps():如果執行數據提取以響應props的更改,請改為componentDidupdate()生命周期,如果是為了在props更改后重置某些state,請考慮組件完全受控或使用key使組件不受控來代替

3:componentWillUpdate():不能在此調用setState(),通常情況下此方法替換成componentDidupdate()。如果想要讀取dom信息(如保存滾動位置)可將邏輯移至getSnapshotBeforeUpdate()中

另外還有個生命周期是不常用的:shouldcomponentUpdate:只作為性能優化的方式存在,不要在這里做阻止渲染等操作會出現bug

注意,你不能此方法中調用 this.setState();在 UNSAFE_componentWillUpdate() 返回之前,你也不應該執行任何其他操作(例如,dispatch Redux 的 action)觸發對 React 組件的更新 

通常,此方法可以替換為 componentDidUpdate()。如果你在此方法中讀取 DOM 信息(例如,為了保存滾動位置),則可以將此邏輯移至 getSnapshotBeforeUpdate() 中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM