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

資訊專欄INFORMATION COLUMN

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

ASCH / 2682人閱讀

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

文章標題總算是可以正常一點了……

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

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

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

內(nèi)容摘要

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

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

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

不要直接使用當前 state 的值生成下一個 state。

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

組件生命周期流程圖。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

所以,直接基于當前 state 的值,生成一下個 state 是不靠譜的,但是很多不清楚這一點的同學基本上都是這么做的,因為寫起來簡單嘛,而且貌似也沒有什么問題。這是因為很多情況下,業(yè)務邏輯沒有那么復雜,基本不會頻繁調(diào)用 setState 。但是這確實是一個隱患,如果在項目初期不注意規(guī)避,等項目復雜到一定程度以后,可能會出現(xiàn)難以排查的BUG。

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

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

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

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

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

生命周期函數(shù)

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

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

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

組件初始化:constructor

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

實例化主要做的事情:

創(chuàng)建一個組件的實例對象(也就是 Element,通常對應一個JSX表達式,如:)。

獲取組件的默認屬性。

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

componentWillMount

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

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

componentDidMount

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

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

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

設置 setInterval、setTimeout 等計時器操作。

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

componentWillReceiveProps
componentWillReceiveProps(nextProps)

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

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

組件沒有收到新的屬性,但是由于父組件重新渲染導致當前組件也被重新渲染。

你只要知道,當該函數(shù)被調(diào)用時,并不一定是因為屬性發(fā)生了變化。

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

shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState)

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

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

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

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

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

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

componentWillUpdate

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

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

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

componentDidUpdate
componentDidUpdate(prevProps, prevState)

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

在此處是做這些事情的好時機:

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

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

componentWillUnmount

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

componentDidCatch
componentDidCatch(error, info)

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

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

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

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

最后(微信群)

這篇文章來的有點慢,非常抱歉。

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

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

我的微信:leobaba88

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

轉載請注明本文地址:http://systransis.cn/yun/51427.html

相關文章

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

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

    Rocture 評論0 收藏0
  • 玩轉 React(一)- 前言

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

    waltr 評論0 收藏0
  • 玩轉 React(四)- 創(chuàng)造一個新 HTML 標簽

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

    soasme 評論0 收藏0
  • 玩轉 React(四)- 創(chuàng)造一個新 HTML 標簽

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

    dendoink 評論0 收藏0

發(fā)表評論

0條評論

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