成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

玩轉(zhuǎn) React(五)- 組件的內(nèi)部狀態(tài)和生命周期

Rocture / 1404人閱讀

摘要:另外本文中會介紹一個(gè)通過類繼承方式定義的組件的生命周期,以及在各個(gè)生命周期函數(shù)中能做什么,不能或盡量不要做什么。各個(gè)生命周期函數(shù)介紹及使用經(jīng)驗(yàn)。獲取組件的初始內(nèi)部狀態(tài)在中。該聲明周期函數(shù)可能在兩種情況下被調(diào)用組件接收到了新的屬性。

文章標(biāo)題總算是可以正常一點(diǎn)了……

通過之前的文章我們已經(jīng)知道:在 React 體系中所謂的 "在 JavaScript 中編寫 HTML 代碼" 指的是 React 擴(kuò)展了 JavaScript 的語法,也就是 JSX。JSX 語法中可以以類似 HTML 語法的方式使用 React 組件,從而編寫 React 組件就有一種創(chuàng)造一個(gè)新的 HTML 標(biāo)簽的體驗(yàn)。

上一篇文章《玩轉(zhuǎn) React(四)- 創(chuàng)造一個(gè)新的 HTML 標(biāo)簽》介紹了如何來創(chuàng)建一個(gè) React 組件,以及組件的屬性。了解到組件的視圖是屬性的映射,通過改變組件屬性可以觸發(fā)組件重新渲染,從而改變組件的視圖。其實(shí)組件的視圖并不僅僅是由屬性映射來的,本篇將介紹另一種可以觸發(fā)組件重新渲染的方式,即組件的內(nèi)部狀態(tài)(state),嚴(yán)格來說組件的視圖是由屬性和內(nèi)部狀態(tài)映射而來的,即:view = f(props, state),跟屬性類似,狀態(tài)的改變也會觸發(fā)組件重新渲染,只不過狀態(tài)是組件內(nèi)部基于自身邏輯或者用戶事件自己維護(hù)的,而不是由外部輸入的。

另外本文中會介紹一個(gè)通過類繼承方式定義的組件的生命周期,以及在各個(gè)生命周期函數(shù)中能做什么,不能或盡量不要做什么。

內(nèi)容摘要

ReactDOM.render 在一個(gè)單頁面 web 應(yīng)用中通常只調(diào)用一次。

組件可以通過 setState 改變內(nèi)部狀態(tài) state 來更新視圖。

setState 多數(shù)情況下是異步的。

不要直接使用當(dāng)前 state 的值生成下一個(gè) state。

不要直接通過 this.state 修改 state

組件生命周期流程圖。

各個(gè)生命周期函數(shù)介紹及使用經(jīng)驗(yàn)。

以上是本文的內(nèi)容摘要,如果你已經(jīng)知道我要說的是什么,那么就沒有必要繼續(xù)看下去了,節(jié)約時(shí)間。

組件的內(nèi)部狀態(tài)

此前,我們已經(jīng)了解到可以通過 ReactDOM.render(, container) 的方式,將帶有特定屬性的組件渲染到頁面的某個(gè) DOM 節(jié)點(diǎn)中(container),這樣頁面上會展示出 “Hello Lucy”,當(dāng)我們希望頁面上展示 “Hello Tom” 的時(shí)候,我們可以將組件的 name 屬性改為 Tom 后再次調(diào)用 ReactDOM.render 方法,這樣組件就會以新的屬性重新渲染,從而更新組件的視圖。

下面是官方文檔中一個(gè)展示時(shí)鐘的例子,我簡單改造了下:

https://codepen.io/Sarike/pen...

例子中定義了一個(gè) Clock 組件,組件接收一個(gè) time 屬性,在組件外部通過 setInterval 周期性地調(diào)用 ReactDOM.render 不斷更新 Clock 的屬性并重新渲染。

然而在很多實(shí)際場景中,對于一個(gè)時(shí)鐘組件,我們希望它有更好的封裝性和復(fù)用性,也就是說我們希望只調(diào)用一次 ReactDOM.render(, container) 然后它可以自己更新自己的視圖,這樣我們就更容易在頁面上放置多個(gè)時(shí)鐘了,即復(fù)用性更好了。

要達(dá)到這個(gè)目的,就需要組件的內(nèi)部狀態(tài)來支持。組件有一個(gè)特殊的屬性 state 用來保存組件的內(nèi)部狀態(tài)。用戶可以通過 this.setState(statePatch) 來更新組件的狀態(tài),組件的狀態(tài)更新后會重新執(zhí)行 render 方法來更新視圖,上面的例子使用內(nèi)部狀態(tài)改造后:

https://codepen.io/Sarike/pen...

這樣 Clock 作為一個(gè)完整的時(shí)鐘組件就可以自己來更新自己了,上篇文中也有提到過,如果想要使用組件的內(nèi)部狀態(tài),那組件必須以類繼承的方式來定義,而不能使用函數(shù)式組件。所以說,函數(shù)式組件經(jīng)常也被稱作是無狀態(tài)組件(stateless)。

上面例子中有用到 componentDidMountcomponentWillUnmount 兩個(gè)函數(shù),它們是組件的生命周期函數(shù),本文的后半部分將會介紹,這倆函數(shù)分別在組件掛載到頁面上和組件將要從頁面上移除時(shí)調(diào)用。

改造后的例子,我們只需要調(diào)用一次 ReactDOM.render 即可,在實(shí)際的項(xiàng)目中,一個(gè)完整的單頁面 web 應(yīng)用,也只需要調(diào)用一次 ReactDOM.render 方法把根組件掛載到頁面中即可,剩下的工作就都放心地交給 React 就行了。

初始化組件內(nèi)部狀態(tài)

在創(chuàng)建一個(gè)擁有內(nèi)部狀態(tài)的組件時(shí),我們需要對內(nèi)部狀態(tài)進(jìn)行初始化,即設(shè)置組件最初的狀態(tài)是什么。做法很簡單,就是在構(gòu)造函數(shù) constructor 中設(shè)置 state 屬性就可以了。如下所示:

class MyComponent extends React.Component {
    constructor(props) {
        super(props); // 這行代碼不能少哦
        this.state = {
            name: "Lucy"
        }
    }
}
setState 大多數(shù)情況下是異步的

setState 多數(shù)情況下是異步的,異步意味著通過 setState 更新組件狀態(tài)后,不能立刻通過 this.state 來獲取到更新之后的值,另外當(dāng)連續(xù)多次調(diào)用 setState 來更新同一個(gè)字段時(shí),只有最后一次更新才會生效。如下示例:

https://codepen.io/Sarike/pen...

如果希望上面示例代碼正常工作,你需要通過回調(diào)函數(shù)的方式來生成下一個(gè) state,如下所示:

this.setState(preState => ({value: preState.value + 1}));
this.setState(preState => ({value: preState.value + 2}));
this.setState(preState => ({value: preState.value + 3}));

所以,直接基于當(dāng)前 state 的值,生成一下個(gè) state 是不靠譜的,但是很多不清楚這一點(diǎn)的同學(xué)基本上都是這么做的,因?yàn)閷懫饋砗唵温?,而且貌似也沒有什么問題。這是因?yàn)楹芏嗲闆r下,業(yè)務(wù)邏輯沒有那么復(fù)雜,基本不會頻繁調(diào)用 setState 。但是這確實(shí)是一個(gè)隱患,如果在項(xiàng)目初期不注意規(guī)避,等項(xiàng)目復(fù)雜到一定程度以后,可能會出現(xiàn)難以排查的BUG。

那為什么說多數(shù)情況下是異步的呢?難道有些情況下不是異步的嗎?是的,實(shí)際上只有在 React 能控制的事件處理過程中調(diào)用的 setState 才是異步的,如:生命周期函數(shù),React 內(nèi)置的如 button,input 等組件的事件處理函數(shù)。在多數(shù)的情況下我們只需要在這些地方控制我們的組件就夠了,所以說大多數(shù)情況下 setState 是異步的。

在某些特殊的組件中,可能需要通過 addEventListener 來設(shè)置某些 DOM 的事件處理函數(shù),在這種通過原生的 JS API 來設(shè)置的事件處理過程調(diào)用 setState 就是同步的,會立即更新 this.state。另外還有 setInterval、setTimeout 等原生 API 的回調(diào)函數(shù)也是如此。

參考:https://www.zhihu.com/questio...

不要直接通過 this.state 來更新組件狀態(tài)

這一點(diǎn)跟屬性類似,直接通過 this.state 修改組件狀態(tài),組件狀態(tài)被修改了,但并不會觸發(fā)組件的重新渲染。這樣就會導(dǎo)致組件視圖與狀態(tài)不一致。

生命周期函數(shù)

一個(gè)組件被我們創(chuàng)造到這個(gè)世界上之后,在使用它時(shí),它的每個(gè)實(shí)例都是有一定生命周期的,下面這張圖說明了一個(gè)組件實(shí)例的生命周期:

圖片來源:https://tylermcginnis.com/an-...,這張圖略微有點(diǎn)老,不過結(jié)合下文來看也沒什么問題。

下面我們來解釋一下上面這張圖。

組件初始化:constructor

我們定義的每一個(gè)組件,都是一個(gè)類(class),這些類被實(shí)例化后才能作為 React DOM 中的一個(gè)節(jié)點(diǎn)渲染到頁面上。所以,當(dāng)我們通過 ReactDOM.render 或者在某個(gè)組件中通過 JSX 表達(dá)式將一個(gè)組件第一次渲染到頁面上時(shí),組件首先要做的就是對組件進(jìn)行實(shí)例化。

實(shí)例化主要做的事情:

創(chuàng)建一個(gè)組件的實(shí)例對象(也就是 Element,通常對應(yīng)一個(gè)JSX表達(dá)式,如:)。

獲取組件的默認(rèn)屬性。

獲取組件的初始內(nèi)部狀態(tài)(在 constructorthis.state = xxxx;)。

componentWillMount

在組件被渲染到頁面上之前執(zhí)行,在組件的整個(gè)生命周期內(nèi)只執(zhí)行一次。在這里可以調(diào)用 setState 更新內(nèi)部狀態(tài),但是更推薦將這里的狀態(tài)更新操作放到 constructor 中。

該函數(shù)執(zhí)行完后會立馬執(zhí)行 render 方法并將組件渲染到頁面上。所以,在這里執(zhí)行 setState 不會觸發(fā)額外的渲染過程,因?yàn)檫@是沒有必要的。

componentDidMount

組件被渲染到頁面上后立馬執(zhí)行,在組件的整個(gè)生命周期內(nèi)只執(zhí)行一次。這個(gè)時(shí)候是做如下操作的好時(shí)機(jī):

某些依賴組件 DOM 節(jié)點(diǎn)的操作。

發(fā)起網(wǎng)絡(luò)請求。

設(shè)置 setInterval、setTimeout 等計(jì)時(shí)器操作。

在這里可以調(diào)用 setState 更新組件內(nèi)部狀態(tài),且會觸發(fā)一個(gè)重新渲染的過程,即會重新執(zhí)行 render 方法并更新視圖。

componentWillReceiveProps
componentWillReceiveProps(nextProps)

該聲明周期函數(shù)可能在兩種情況下被調(diào)用:

組件接收到了新的屬性。新的屬性會通過 nextProps 獲取到。

組件沒有收到新的屬性,但是由于父組件重新渲染導(dǎo)致當(dāng)前組件也被重新渲染。

你只要知道,當(dāng)該函數(shù)被調(diào)用時(shí),并不一定是因?yàn)閷傩园l(fā)生了變化。

在這里也可以調(diào)用 setState 更新組件的內(nèi)部狀態(tài),同樣也不會觸發(fā)額外的重新渲染操作,React 會聰明地用更新后的屬性和內(nèi)部狀態(tài)進(jìn)行一次重新渲染。

shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState)

這是一個(gè)詢問式的生命周期函數(shù),所以該函數(shù)需要一個(gè)返回值 true/false,如果為 true,組件將觸發(fā)重新渲染過程,如果為 false 組件將不會觸發(fā)重新渲染。因此,合理地利用該函數(shù)可以一定程度節(jié)省開銷,提高系統(tǒng)的性能。

此處不能調(diào)用 setState 更新組件的狀態(tài)。

由于組件屬性或者內(nèi)部狀態(tài)被改變時(shí)都觸發(fā)組件重新渲染,所以該函數(shù)接受兩個(gè)參數(shù):新的屬性(nextProps)、新的狀態(tài)(nextState)。

在處理該聲明周期函數(shù)時(shí),切記要兼顧屬性和狀態(tài),不能只顧其一,不然很容易踩坑。例如:某位同學(xué)只依據(jù)屬性來判斷是否觸發(fā)重新渲染,而忽略了內(nèi)部狀態(tài),這樣就導(dǎo)致你無論如何 setState,組件視圖都不能正常更新。

在上篇文章中我們提到類繼承方式定義組件時(shí)說到,React 提供了兩個(gè)基類,一個(gè)是 Component,另一個(gè)是 PureComponent,兩者的差別就在于后者已經(jīng)幫我們簡單實(shí)現(xiàn)了一下 shouldComponentUpdate 函數(shù),當(dāng)屬性和狀態(tài)都沒有發(fā)生變化時(shí)返回 false 以避免額外的開銷。

但是比對過程出于性能考慮,只是進(jìn)行淺比對,也就是只比對對象的第一級字段,而且是否發(fā)生變化是通過 Object.is 方法類判斷的。所以會導(dǎo)致有時(shí)候發(fā)生變化了組件沒有更新,沒有變化卻觸發(fā)了重新渲染過程。這個(gè)在這里不再贅述,想深入探討可以掃描問候的二維碼加我微信好友(我的微信:leobaba88)。

componentWillUpdate

當(dāng)組件 shouldComponentUpdate 返回 true 或者調(diào)用 forceUpdate 時(shí)將觸發(fā)此函數(shù)。

該函數(shù)中不能調(diào)用 setState 更新組件狀態(tài),當(dāng)你想這么做的時(shí)候,你可以考慮將它移到 componentWillReceiveProps 函數(shù)里。

該函數(shù)在函數(shù)第一次渲染的時(shí)候不會執(zhí)行。

componentDidUpdate
componentDidUpdate(prevProps, prevState)

在組件重新渲染過程中,重新執(zhí)行 render 方法并更新組件視圖后立即執(zhí)行該函數(shù)。類似組件第一次渲染過程中的 componentDidMount,該函數(shù)在第一次渲染時(shí)不會執(zhí)行。

在此處是做這些事情的好時(shí)機(jī):

執(zhí)行依賴新 DOM 節(jié)點(diǎn)的操作。

依據(jù)新的屬性發(fā)起新的網(wǎng)絡(luò)請求。(但是此處一定要格外謹(jǐn)慎,一定要在確認(rèn)屬性變化后再發(fā)起網(wǎng)絡(luò)請求,不然極有可能進(jìn)入死循環(huán):didUpdate -> ajax -> changeProps -> didUpdate -> ...)。

componentWillUnmount

當(dāng)組件被從頁面中移除之前調(diào)用,此時(shí)是清理戰(zhàn)場的好時(shí)機(jī),如清理定時(shí)器、終止網(wǎng)絡(luò)請求等。

componentDidCatch
componentDidCatch(error, info)

這是 React 16 新加入的一個(gè)生命周期函數(shù)。定義該生命周期函數(shù)的組件將會成為一個(gè)錯(cuò)誤邊界,錯(cuò)誤邊界這個(gè)詞非常形象,它可以有效地將錯(cuò)誤限制在一個(gè)有限的范圍內(nèi),而不會導(dǎo)致整個(gè)應(yīng)用崩潰,防止一顆耗子屎壞了一鍋湯。

錯(cuò)誤邊界組件,可以捕獲其整個(gè)子組件樹內(nèi)發(fā)生的任何異常,但是卻不能捕獲自身的異常。

下面是官方的一個(gè)示例,大家感受下:

https://codepen.io/gaearon/pe...

最后(微信群)

這篇文章來的有點(diǎn)慢,非常抱歉。

另外為了方便大家閱讀,我將所有文章的鏈接更新到第一篇文章 《玩轉(zhuǎn)React(一)- 前言》 中。

文字的表現(xiàn)范圍畢竟有限,為了方便大家交流,我建了一個(gè)微信群,對 React 感興趣的同學(xué)可以進(jìn)群一起交流、學(xué)習(xí),由于微信群邀請的時(shí)間限制,大家可以先掃描下面二維碼,加我好友,我拉大家進(jìn)群:

我的微信:leobaba88

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/91996.html

相關(guān)文章

  • 玩轉(zhuǎn) React)- 組件內(nèi)部狀態(tài)生命周期

    摘要:另外本文中會介紹一個(gè)通過類繼承方式定義的組件的生命周期,以及在各個(gè)生命周期函數(shù)中能做什么,不能或盡量不要做什么。各個(gè)生命周期函數(shù)介紹及使用經(jīng)驗(yàn)。獲取組件的初始內(nèi)部狀態(tài)在中。該聲明周期函數(shù)可能在兩種情況下被調(diào)用組件接收到了新的屬性。 文章標(biāo)題總算是可以正常一點(diǎn)了…… 通過之前的文章我們已經(jīng)知道:在 React 體系中所謂的 在 JavaScript 中編寫 HTML 代碼 指的是 Rea...

    ASCH 評論0 收藏0
  • 玩轉(zhuǎn) React(一)- 前言

    摘要:本人計(jì)劃編寫一個(gè)針對中初級前端開發(fā)者學(xué)習(xí)的系列教程玩轉(zhuǎn)。使用的原因是新的語言規(guī)范開發(fā)效率更高代碼更優(yōu)雅,尤其是基于開發(fā)的項(xiàng)目。其次也是目前特別流行的一個(gè)前端框架,截止目前,上有將近萬,國內(nèi)一二線互聯(lián)網(wǎng)公司都有深度依賴開發(fā)的項(xiàng)目。 本人計(jì)劃編寫一個(gè)針對中初級前端開發(fā)者學(xué)習(xí) React 的系列教程 - 《玩轉(zhuǎn) React》。 文章更新頻率:每周 1 ~ 2 篇。 目錄 玩轉(zhuǎn) React(...

    waltr 評論0 收藏0
  • 玩轉(zhuǎn) React(四)- 創(chuàng)造一個(gè)新 HTML 標(biāo)簽

    摘要:屬性是一個(gè)組件的外部輸入。只會在開發(fā)模式下進(jìn)行屬性類型檢查,當(dāng)代碼進(jìn)行生產(chǎn)發(fā)布后,為了減少額外的性能開銷,類型檢查將會被略過。某個(gè)類的實(shí)例枚舉,屬性值必須為其中的某一個(gè)值。屬性為一個(gè)數(shù)組,且數(shù)組中的元素必須符合指定類型。 在第二篇文章 《新型前端開發(fā)方式》 中有說到 React 有很爽的一點(diǎn)就是給我們一種創(chuàng)造 HTML 標(biāo)簽的能力,那么今天這篇文章就詳細(xì)講解下 React 是如何提供這...

    soasme 評論0 收藏0
  • 玩轉(zhuǎn) React(四)- 創(chuàng)造一個(gè)新 HTML 標(biāo)簽

    摘要:屬性是一個(gè)組件的外部輸入。只會在開發(fā)模式下進(jìn)行屬性類型檢查,當(dāng)代碼進(jìn)行生產(chǎn)發(fā)布后,為了減少額外的性能開銷,類型檢查將會被略過。某個(gè)類的實(shí)例枚舉,屬性值必須為其中的某一個(gè)值。屬性為一個(gè)數(shù)組,且數(shù)組中的元素必須符合指定類型。 在第二篇文章 《新型前端開發(fā)方式》 中有說到 React 有很爽的一點(diǎn)就是給我們一種創(chuàng)造 HTML 標(biāo)簽的能力,那么今天這篇文章就詳細(xì)講解下 React 是如何提供這...

    dendoink 評論0 收藏0

發(fā)表評論

0條評論

Rocture

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<