摘要:因?yàn)槭巧钊胂盗形恼拢疚牟粫?huì)仔細(xì)介紹每個(gè)生命周期方法的使用,而是會(huì)重點(diǎn)講解在使用組件生命周期時(shí),經(jīng)常遇到的疑問和錯(cuò)誤使用方式。父組件發(fā)生更新導(dǎo)致的組件更新,生命周期方法的調(diào)用情況同上所述。
React 深入系列,深入講解了React中的重點(diǎn)概念、特性和模式等,旨在幫助大家加深對(duì)React的理解,以及在項(xiàng)目中更加靈活地使用React。
組件是構(gòu)建React應(yīng)用的基本單位,組件需要具備數(shù)據(jù)獲取、業(yè)務(wù)邏輯處理、以及UI呈現(xiàn)的能力,而這些能力是要依賴于組件不同的生命周期方法的。組件的生命周期分為3個(gè)階段:掛載階段、更新階段、卸載階段,每個(gè)階段都包含相應(yīng)的生命周期方法。因?yàn)槭巧钊胂盗形恼拢疚牟粫?huì)仔細(xì)介紹每個(gè)生命周期方法的使用,而是會(huì)重點(diǎn)講解在使用組件生命周期時(shí),經(jīng)常遇到的疑問和錯(cuò)誤使用方式。
服務(wù)器數(shù)據(jù)請(qǐng)求初學(xué)者在使用React時(shí),常常不知道何時(shí)向服務(wù)器發(fā)送請(qǐng)求,獲取組件所需數(shù)據(jù)。對(duì)于組件所需的初始數(shù)據(jù),最合適的地方,是在componentDidMount方法中,進(jìn)行數(shù)據(jù)請(qǐng)求,這個(gè)時(shí)候,組件完成掛載,其代表的DOM已經(jīng)掛載到頁面的DOM樹上,即使獲取到的數(shù)據(jù)需要直接操作DOM節(jié)點(diǎn),這個(gè)時(shí)候也是絕對(duì)安全的。有些人還習(xí)慣在constructor或者componentWillMount中,進(jìn)行數(shù)據(jù)請(qǐng)求,認(rèn)為這樣可以更快的獲取到數(shù)據(jù),但它們相比componentDidMount的執(zhí)行時(shí)間,提前的時(shí)間實(shí)在是太微乎其微了。另外,當(dāng)進(jìn)行服務(wù)器渲染時(shí)(SSR),componentWillMount是會(huì)被調(diào)用兩次的,一次在服務(wù)器端,一次在客戶端,這時(shí)候就會(huì)導(dǎo)致額外的請(qǐng)求發(fā)生。
組件進(jìn)行數(shù)據(jù)請(qǐng)求的另一種場景:由父組件的更新導(dǎo)致組件的props發(fā)生變化,如果組件的數(shù)據(jù)請(qǐng)求依賴props,組件就需要重新進(jìn)行數(shù)據(jù)請(qǐng)求。例如,新聞詳情組件NewsDetail,在獲取新聞詳情數(shù)據(jù)時(shí),需要傳遞新聞的id作為參數(shù)給服務(wù)器端,當(dāng)NewsDetail已經(jīng)處于掛載狀態(tài)時(shí),如果點(diǎn)擊其他新聞,NewsDetail的componentDidMount并不會(huì)重新調(diào)用,因而componentDidMount中進(jìn)行新聞詳情數(shù)據(jù)請(qǐng)求的方法也不會(huì)再次執(zhí)行。這時(shí)候,應(yīng)該在componentWillReceiveProps中,進(jìn)行數(shù)據(jù)請(qǐng)求:
componentWillReceiveProps(nextProps) { if(this.props.newId !== nextProps.newsId) { fetchNewsDetailById(nextProps.newsId) // 根據(jù)最新的新聞id,請(qǐng)求新聞詳情數(shù)據(jù) } }
如果進(jìn)行數(shù)據(jù)請(qǐng)求的時(shí)機(jī)是由頁面上的交互行為觸發(fā)的,例如,點(diǎn)擊查詢按鈕后,查詢數(shù)據(jù),這時(shí)只需要在查詢按鈕的事件監(jiān)聽函數(shù)中,執(zhí)行數(shù)據(jù)請(qǐng)求即可,這種情況一般是不會(huì)有疑問的。
更新階段方法的調(diào)用組件的更新是組件生命周期中最復(fù)雜的階段,也是涉及到最多生命周期方法的階段。
正常情況下,當(dāng)組件發(fā)生更新時(shí),組件的生命周期方法的調(diào)用順序如下:
componentWillReceiveProps -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate // 組件收到新的props(props中的數(shù)據(jù)并不一定真正發(fā)生變化)-> 決定是否需要繼續(xù)執(zhí)行更新過程 -> 組件代表的虛擬DOM即將更新 -> 組件重新計(jì)算出新的虛擬DOM -> 虛擬DOM對(duì)應(yīng)的真實(shí)DOM更新到真實(shí)DOM樹中
父組件發(fā)生更新或組件自身調(diào)用setState,都會(huì)導(dǎo)致組件進(jìn)行更新操作。父組件發(fā)生更新導(dǎo)致的組件更新,生命周期方法的調(diào)用情況同上所述。如果是組件自身調(diào)用setState,導(dǎo)致的組件更新,其生命周期方法的調(diào)用情況如下:
shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
可見,這種情況下componentWillReceiveProps并不會(huì)被調(diào)用。
當(dāng)組件的shouldComponentUpdate返回false時(shí),組件會(huì)停止更新過程,這時(shí)候生命周期方法的調(diào)用順序如下:
componentWillReceiveProps -> shouldComponentUpdate -> 結(jié)束
或(組件自身調(diào)用setState,導(dǎo)致的組件更新):
shouldComponentUpdate -> 結(jié)束setState的時(shí)機(jī)
組件的生命周期方法眾多,哪些方法中可以調(diào)用setState更新組件狀態(tài)?哪些方法中不可以呢?
可以的方法
componentWillMount、componentDidMount、componentWillReceiveProps、componentDidUpdate
這里有幾個(gè)注意點(diǎn):
componentWillMount 中同步調(diào)用setState不會(huì)導(dǎo)致組件進(jìn)行額外的渲染,組件經(jīng)歷的生命周期方法依次是componentWillMount -> render -> componentDidMount,組件并不會(huì)因?yàn)閏omponentWillMount中的setState調(diào)用再次進(jìn)行更新操作。如果是異步調(diào)用setState,組件是會(huì)進(jìn)行額外的更新操作。不過實(shí)際場景中很少在componentWillMount中調(diào)用setState,一般可以通過直接在constructor中定義state的方式代替。
一般情況下,當(dāng)調(diào)用setState后,組件會(huì)執(zhí)行一次更新過程,componentWillReceiveProps等更新階段的方法會(huì)再次被調(diào)用,但如果在componentWillReceiveProps中調(diào)用setState,并不會(huì)額外導(dǎo)致一次新的更新過程,也就是說,當(dāng)前的更新過程結(jié)束后,componentWillReceiveProps等更新階段的方法不會(huì)再被調(diào)用一次。(注意,這里仍然指同步調(diào)用setState,如果是異步調(diào)用,則會(huì)導(dǎo)致組件再次進(jìn)行渲染)
componentDidUpdate中調(diào)用setState要格外小心,在setState前必須有條件判斷,只有滿足了相應(yīng)條件,才setState,否組組件會(huì)不斷執(zhí)行更新過程,進(jìn)入死循環(huán)。因?yàn)閟etState會(huì)導(dǎo)致新一次的組件更新,組件更新完成后,componentDidUpdate被調(diào)用,又繼續(xù)setState,死循環(huán)就產(chǎn)生了。
不可以的方法
其他生命周期方法都不能調(diào)用setState,主要原因有兩個(gè):
產(chǎn)生死循環(huán)。例如,shouldComponentUpdate、componentWillUpdate 和 render 中調(diào)用setState,組件本次的更新還沒有執(zhí)行完成,又會(huì)進(jìn)入新一輪的更新,導(dǎo)致不斷循環(huán)更新,進(jìn)入死循環(huán)。
無意義。componentWillUnmount 調(diào)用時(shí),組件即將被卸載,setState是為了更新組件,在一個(gè)即將卸載的組件上更新state顯然是無意義的。實(shí)際上,在componentWillUnmount中調(diào)用setState也是會(huì)拋出異常的。
render次數(shù) != 瀏覽器界面更新次數(shù)先看下面的一個(gè)例子:
class App extends React.Component { constructor(props) { super(props) this.state = { bgColor: "red" } } render() { var {bgColor} = this.state return (Test); } componentDidMount() { this.setState({ bgColor: "yellow" }) } }
當(dāng)我們觀察瀏覽器渲染出的頁面時(shí),頁面中Test所在div的背景色,是先顯示紅色,再變成黃色呢?還是直接就顯示為黃色呢?
答案是:直接就顯示為黃色!
這個(gè)過程中,組件的生命周期方法被調(diào)用的順序如下:
constructor -> componentWillMount -> render -> componentDidMount -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
組件在掛載完成后,因?yàn)閟etState的調(diào)用,將立即執(zhí)行一次更新過程。雖然render方法被調(diào)用了兩次,但這并不會(huì)導(dǎo)致瀏覽器界面更新兩次,實(shí)際上,兩次DOM的修改會(huì)合并成一次瀏覽器界面的更新。React官網(wǎng)介紹componentDidMount方法時(shí)也有以下說明:
Calling setState() in this method will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state.
這說明,組件render的次數(shù) 不一定等于 瀏覽器界面更新次數(shù)。雖然JS的執(zhí)行和DOM的渲染分別由瀏覽器不同的線程完成,但JS的執(zhí)行會(huì)阻塞DOM的渲染,而上面的兩次render是在一個(gè)JS事件周期內(nèi)執(zhí)行的,所以在兩次render結(jié)束前,瀏覽器不會(huì)更新界面。
下篇預(yù)告:React 深入系列5:事件處理
我的新書《React進(jìn)階之路》已上市,請(qǐng)大家多多支持!
鏈接:京東 當(dāng)當(dāng)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/95198.html
摘要:因?yàn)槭巧钊胂盗形恼拢疚牟粫?huì)仔細(xì)介紹每個(gè)生命周期方法的使用,而是會(huì)重點(diǎn)講解在使用組件生命周期時(shí),經(jīng)常遇到的疑問和錯(cuò)誤使用方式。父組件發(fā)生更新導(dǎo)致的組件更新,生命周期方法的調(diào)用情況同上所述。 文:徐超,《React進(jìn)階之路》作者授權(quán)發(fā)布,轉(zhuǎn)載請(qǐng)注明作者及出處 React 深入系列4:組件的生命周期 React 深入系列,深入講解了React中的重點(diǎn)概念、特性和模式等,旨在幫助大家加深...
摘要:用于規(guī)范的類型與必需的狀態(tài)。表示由組件更改的數(shù)據(jù),通常是通過與用戶的交互來更改的。為了實(shí)現(xiàn)的修改,需要注冊(cè)事件處理程序到相應(yīng)的元素上。當(dāng)事件發(fā)生時(shí),將更新后的值是從中檢索,并通知組件。通常情況下,該函數(shù)初始化狀態(tài)使用,,或其他數(shù)據(jù)存儲(chǔ)。 前言 上一篇文章中,我們講到了JSX的一些用法和注意事項(xiàng),這次我們來講react中最基礎(chǔ)也是特別重要的內(nèi)容:組件。這篇文章包含組件的以下內(nèi)容:狀態(tài)、屬...
摘要:當(dāng)真正執(zhí)行狀態(tài)修改時(shí),依賴的并不能保證是最新的,因?yàn)闀?huì)把多次的修改合并成一次,這時(shí),還是等于這幾次修改發(fā)生前的。下篇預(yù)告深入系列組件的生命周期新書推薦進(jìn)階之路作者徐超畢業(yè)于浙江大學(xué),碩士,資深前端工程師,長期就職于能源物聯(lián)網(wǎng)公司遠(yuǎn)景智能。 文:徐超,《React進(jìn)階之路》作者授權(quán)發(fā)布,轉(zhuǎn)載請(qǐng)注明作者及出處 React 深入系列3:Props 和 State React 深入系列,深...
摘要:深入系列,深入講解了中的重點(diǎn)概念特性和模式等,旨在幫助大家加深對(duì)的理解,以及在項(xiàng)目中更加靈活地使用。下篇預(yù)告深入系列組件的生命周期我的新書進(jìn)階之路已上市,請(qǐng)大家多多支持鏈接京東當(dāng)當(dāng) React 深入系列,深入講解了React中的重點(diǎn)概念、特性和模式等,旨在幫助大家加深對(duì)React的理解,以及在項(xiàng)目中更加靈活地使用React。 React 的核心思想是組件化的思想,而React 組件的定...
摘要:在項(xiàng)目中用好高階組件,可以顯著提高代碼質(zhì)量。高階組件的定義類比于高階函數(shù)的定義。高階函數(shù)接收函數(shù)作為參數(shù),并且返回值也是一個(gè)函數(shù)。 React 深入系列,深入講解了React中的重點(diǎn)概念、特性和模式等,旨在幫助大家加深對(duì)React的理解,以及在項(xiàng)目中更加靈活地使用React。 1. 基本概念 高階組件是React 中一個(gè)很重要且比較復(fù)雜的概念,高階組件在很多第三方庫(如Redux)中都...
閱讀 657·2021-11-22 15:32
閱讀 2744·2021-11-19 09:40
閱讀 2337·2021-11-17 09:33
閱讀 1299·2021-11-15 11:36
閱讀 1895·2021-10-11 10:59
閱讀 1502·2019-08-29 16:41
閱讀 1808·2019-08-29 13:45
閱讀 2181·2019-08-26 13:36