摘要:因?yàn)槭巧钊胂盗形恼?,本文不?huì)仔細(xì)介紹每個(gè)生命周期方法的使用,而是會(huì)重點(diǎn)講解在使用組件生命周期時(shí),經(jīng)常遇到的疑問(wèn)和錯(cuò)誤使用方式。父組件發(fā)生更新導(dǎo)致的組件更新,生命周期方法的調(diào)用情況同上所述。
文:徐超,《React進(jìn)階之路》作者React 深入系列4:組件的生命周期授權(quán)發(fā)布,轉(zhuǎn)載請(qǐng)注明作者及出處
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)常遇到的疑問(wèn)和錯(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)掛載到頁(yè)面的DOM樹(shù)上,即使獲取到的數(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)求的另一種場(chǎ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ī)是由頁(yè)面上的交互行為觸發(fā)的,例如,點(diǎn)擊查詢按鈕后,查詢數(shù)據(jù),這時(shí)只需要在查詢按鈕的事件監(jiān)聽(tīng)函數(shù)中,執(zhí)行數(shù)據(jù)請(qǐng)求即可,這種情況一般是不會(huì)有疑問(wèn)的。
更新階段方法的調(diào)用組件的更新是組件生命周期中最復(fù)雜的階段,也是涉及到最多生命周期方法的階段。
正常情況下,當(dāng)組件發(fā)生更新時(shí),組件的生命周期方法的調(diào)用順序如下:
componentWillReceiveProps -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate // 組件收到新的props(props中的數(shù)據(jù)并不一定真正發(fā)生變化)-> 決定是否需要繼續(xù)執(zhí)行更新過(guò)程 -> 組件代表的虛擬DOM即將更新 -> 組件重新計(jì)算出新的虛擬DOM -> 虛擬DOM對(duì)應(yīng)的真實(shí)DOM更新到真實(shí)DOM樹(shù)中
父組件發(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
可見(jiàn),這種情況下componentWillReceiveProps并不會(huì)被調(diào)用。
當(dāng)組件的shouldComponentUpdate返回false時(shí),組件會(huì)停止更新過(guò)程,這時(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)行額外的更新操作。不過(guò)實(shí)際場(chǎng)景中很少在componentWillMount中調(diào)用setState,一般可以通過(guò)直接在constructor中定義state的方式代替。
一般情況下,當(dāng)調(diào)用setState后,組件會(huì)執(zhí)行一次更新過(guò)程,componentWillReceiveProps等更新階段的方法會(huì)再次被調(diào)用,但如果在componentWillReceiveProps中調(diào)用setState,并不會(huì)額外導(dǎo)致一次新的更新過(guò)程,也就是說(shuō),當(dāng)前的更新過(guò)程結(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í)行更新過(guò)程,進(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,組件本次的更新還沒(méi)有執(zhí)行完成,又會(huì)進(jìn)入新一輪的更新,導(dǎo)致不斷循環(huán)更新,進(jìn)入死循環(huán)。
無(wú)意義。componentWillUnmount 調(diào)用時(shí),組件即將被卸載,setState是為了更新組件,在一個(gè)即將卸載的組件上更新state顯然是無(wú)意義的。實(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)我們觀察瀏覽器渲染出的頁(yè)面時(shí),頁(yè)面中Test所在div的背景色,是先顯示紅色,再變成黃色呢?還是直接就顯示為黃色呢?
答案是:直接就顯示為黃色!
這個(gè)過(guò)程中,組件的生命周期方法被調(diào)用的順序如下:
constructor -> componentWillMount -> render -> componentDidMount -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
組件在掛載完成后,因?yàn)閟etState的調(diào)用,將立即執(zhí)行一次更新過(guò)程。雖然render方法被調(diào)用了兩次,但這并不會(huì)導(dǎo)致瀏覽器界面更新兩次,實(shí)際上,兩次DOM的修改會(huì)合并成一次瀏覽器界面的更新。React官網(wǎng)介紹componentDidMount方法時(shí)也有以下說(shuō)明:
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.
這說(shuō)明,組件render的次數(shù) 不一定等于 瀏覽器界面更新次數(shù)。雖然JS的執(zhí)行和DOM的渲染分別由瀏覽器不同的線程完成,但JS的執(zhí)行會(huì)阻塞DOM的渲染,而上面的兩次render是在一個(gè)JS事件周期內(nèi)執(zhí)行的,所以在兩次render結(jié)束前,瀏覽器不會(huì)更新界面。
下篇預(yù)告:React 深入系列5:事件處理
新書(shū)推薦《React進(jìn)階之路》
作者:徐超
畢業(yè)于浙江大學(xué),碩士,資深前端工程師,長(zhǎng)期就職于能源物聯(lián)網(wǎng)公司遠(yuǎn)景智能。8年軟件開(kāi)發(fā)經(jīng)驗(yàn),熟悉大前端技術(shù),擁有豐富的Web前端和移動(dòng)端開(kāi)發(fā)經(jīng)驗(yàn),尤其對(duì)React技術(shù)棧和移動(dòng)Hybrid開(kāi)發(fā)技術(shù)有深入的理解和實(shí)踐經(jīng)驗(yàn)。
美團(tuán)點(diǎn)評(píng)廣告平臺(tái)大前端團(tuán)隊(duì)招收20192020年前端實(shí)習(xí)生(偏動(dòng)效方向)
有意者郵件:yao.zhou@meituan.com
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/94531.html
摘要:因?yàn)槭巧钊胂盗形恼拢疚牟粫?huì)仔細(xì)介紹每個(gè)生命周期方法的使用,而是會(huì)重點(diǎn)講解在使用組件生命周期時(shí),經(jīng)常遇到的疑問(wèn)和錯(cuò)誤使用方式。父組件發(fā)生更新導(dǎo)致的組件更新,生命周期方法的調(diào)用情況同上所述。 React 深入系列,深入講解了React中的重點(diǎn)概念、特性和模式等,旨在幫助大家加深對(duì)React的理解,以及在項(xiàng)目中更加靈活地使用React。 組件是構(gòu)建React應(yīng)用的基本單位,組件需要具備數(shù)據(jù)...
摘要:用于規(guī)范的類型與必需的狀態(tài)。表示由組件更改的數(shù)據(jù),通常是通過(guò)與用戶的交互來(lái)更改的。為了實(shí)現(xiàn)的修改,需要注冊(cè)事件處理程序到相應(yīng)的元素上。當(dāng)事件發(fā)生時(shí),將更新后的值是從中檢索,并通知組件。通常情況下,該函數(shù)初始化狀態(tài)使用,,或其他數(shù)據(jù)存儲(chǔ)。 前言 上一篇文章中,我們講到了JSX的一些用法和注意事項(xiàng),這次我們來(lái)講react中最基礎(chǔ)也是特別重要的內(nèi)容:組件。這篇文章包含組件的以下內(nèi)容:狀態(tài)、屬...
摘要:所以對(duì)于組件更新階段的組件生命周期,我們簡(jiǎn)單提及并且提供一些資料給大家。這里為了知識(shí)的完整,補(bǔ)充關(guān)于更新階段的組件生命周期你可以通過(guò)這個(gè)方法控制組件是否重新渲染。大家對(duì)這更新階段的生命周期比較感興趣的話可以查看官網(wǎng)文檔。 React.js 小書(shū) Lesson20 - 更新階段的組件生命周期 本文作者:胡子大哈本文原文:http://huziketang.com/books/react...
摘要:異步實(shí)戰(zhàn)狀態(tài)管理與組件通信組件通信其他狀態(tài)管理當(dāng)需要改變應(yīng)用的狀態(tài)或有需要更新時(shí),你需要觸發(fā)一個(gè)把和載荷封裝成一個(gè)。的行為是同步的。所有的狀態(tài)變化必須通過(guò)通道。前端路由實(shí)現(xiàn)與源碼分析設(shè)計(jì)思想應(yīng)用是一個(gè)狀態(tài)機(jī),視圖與狀態(tài)是一一對(duì)應(yīng)的。 React實(shí)戰(zhàn)與原理筆記 概念與工具集 jsx語(yǔ)法糖;cli;state管理;jest單元測(cè)試; webpack-bundle-analyzer Sto...
摘要:當(dāng)真正執(zhí)行狀態(tài)修改時(shí),依賴的并不能保證是最新的,因?yàn)闀?huì)把多次的修改合并成一次,這時(shí),還是等于這幾次修改發(fā)生前的。下篇預(yù)告深入系列組件的生命周期新書(shū)推薦進(jìn)階之路作者徐超畢業(yè)于浙江大學(xué),碩士,資深前端工程師,長(zhǎng)期就職于能源物聯(lián)網(wǎng)公司遠(yuǎn)景智能。 文:徐超,《React進(jìn)階之路》作者授權(quán)發(fā)布,轉(zhuǎn)載請(qǐng)注明作者及出處 React 深入系列3:Props 和 State React 深入系列,深...
閱讀 3640·2023-04-26 02:07
閱讀 3150·2021-09-22 15:55
閱讀 2534·2021-07-26 23:38
閱讀 3119·2019-08-29 15:16
閱讀 2008·2019-08-29 11:16
閱讀 1746·2019-08-29 11:00
閱讀 3583·2019-08-26 18:36
閱讀 3165·2019-08-26 13:32