国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

玩轉 React(五)- 組件的內部狀態和生命周期

Rocture / 1397人閱讀

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

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

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

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

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

內容摘要

ReactDOM.render 在一個單頁面 web 應用中通常只調用一次。

組件可以通過 setState 改變內部狀態 state 來更新視圖。

setState 多數情況下是異步的。

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

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

組件生命周期流程圖。

各個生命周期函數介紹及使用經驗。

以上是本文的內容摘要,如果你已經知道我要說的是什么,那么就沒有必要繼續看下去了,節約時間。

組件的內部狀態

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

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

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

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

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

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

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

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

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

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

初始化組件內部狀態

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

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

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

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

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

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

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

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

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

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

不要直接通過 this.state 來更新組件狀態

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

生命周期函數

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

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

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

組件初始化:constructor

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

實例化主要做的事情:

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

獲取組件的默認屬性。

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

componentWillMount

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

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

componentDidMount

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

某些依賴組件 DOM 節點的操作。

發起網絡請求。

設置 setIntervalsetTimeout 等計時器操作。

在這里可以調用 setState 更新組件內部狀態,且會觸發一個重新渲染的過程,即會重新執行 render 方法并更新視圖。

componentWillReceiveProps
componentWillReceiveProps(nextProps)

該聲明周期函數可能在兩種情況下被調用:

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

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

你只要知道,當該函數被調用時,并不一定是因為屬性發生了變化

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

shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState)

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

此處不能調用 setState 更新組件的狀態。

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

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

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

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

componentWillUpdate

當組件 shouldComponentUpdate 返回 true 或者調用 forceUpdate 時將觸發此函數。

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

該函數在函數第一次渲染的時候不會執行。

componentDidUpdate
componentDidUpdate(prevProps, prevState)

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

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

執行依賴新 DOM 節點的操作。

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

componentWillUnmount

當組件被從頁面中移除之前調用,此時是清理戰場的好時機,如清理定時器、終止網絡請求等。

componentDidCatch
componentDidCatch(error, info)

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

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

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

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

最后(微信群)

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

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

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

我的微信:leobaba88

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

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91996.html

相關文章

  • 玩轉 React)- 組件內部狀態生命周期

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

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

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

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

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

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

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

    dendoink 評論0 收藏0

發表評論

0條評論

Rocture

|高級講師

TA的文章

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