React 狀態管理 狀態與生命週期

2021-09-11 11:16:18 字數 4533 閱讀 2027

在《react 狀態管理:從 props 和 state 說起》一篇中,我們介紹了乙個 react 元件狀態管理的基礎:props 和 state,以及這兩個物件對 react 元件渲染的影響。在這一篇裡,我們來看看這兩個物件在元件的生命週期中,是如何與元件相互作用的。

生命週期是乙個很寬泛的概念。小到乙個物件,大到乙個應用,都有生命週期。而對於 ui 層面的開發來說,不管是 ios 中view controller,android 中的activity/fragment,還是 react/vue 中的ui 元件,也都有涉及到生命週期。這些物件的生命週期除了建立、銷毀外,可能還涉及到一系列的操作,如載入、顯示、更新、解除安裝等。

在 react 中,元件生命週期的維護一般是由框架負責的,包括元件的建立、銷毀、變更等操作,我們一般不需要直接去手動去做處理。不過,框架同時也會提供一些hook 方法,讓我們在元件生命週期的某些特定時間點,可以加入我們自己的操作。

對於 react 元件來說,生命週期主要包含三個階段:建立(掛載)過程、銷毀(解除安裝)過程和存在期,每個階段都有相應的 hook 方法,我們可以用一張圖來概括:

我們在這不詳細介紹每乙個方法,而是主要介紹 props 和 state 兩個物件是如何參與整個元件的生命週期的。

在這裡需要重提一下render()方法。render() 方法是乙個 class 元件必須實現的方法。props 和 state 物件中的值的改變會引起元件的重新渲染,從而會呼叫元件的 render() 方法。在這個方法中,我們可以從 props 和 state 中取出值來使用,以確定元件如何去渲染。

需要注意的是,render() 必須是乙個純函式,不能在這裡面修改元件的狀態或執行有***的操作。

props 物件定義了元件的屬性,我們在父元件中建立某個元件的例項時,可以通過屬性向這個元件傳遞值。父元件通過屬性傳入的值,都會以key-value的形式儲存在元件的 props 物件中。

首先,我們可以為元件的屬性設定預設值,這樣父元件建立元件時,不需要設定所有的屬性值。此時,元件內部使用 props 中的值時,如果父元件沒有設定,則會使用預設值。

在 es6 的類中,我們可以通過以下方式來設定預設值:

class

greeting

extends

react.component

greeting.defaultprops = ;

複製**

這裡需要注意的是,defaultprops是 greeting 元件本身的屬性(類屬性),而不是元件例項的屬性,這也就意味著在整個應用中,defaultprops 的值只會設定一次,而且是在例項化元件之前。讓我們更直觀地來看看這個流程:

class

component

extends

react.component

}component.defaultprops = ;

const container = document.createelement('div');

const instance = reactdom.render(

react.createelement(component, ),

container,

);複製**

在通過react.createelement()建立元件例項之前,defaultprops 就已經設定好了。這就涉及到另乙個問題,我們可以使用 static 語法糖在 class 內部來設定 defaultprops,此時我們不能在 defaultprops 中使用this去引用例項的屬性(相信有物件導向語言基礎的童鞋都知道問題所在)。

class

component

extends

react.component

render()

}複製**

修改 props 物件中某個屬性值,會引發元件的重新渲染。在這一過程中,會呼叫一系列的 hook 方法,如上圖中所示。這個流程 state 的變更是差不多的。只是 props 的流程多了乙個方法componentwillreceiveprops()。實際上,在當前版本的 react 中,這個方法已被重新命名為unsafe_componentwillreceiveprops(nextprops),其引數 nextprops 包含修改後的新的屬性值。該方法會在元件接收到新的屬性值之前呼叫。

在這個方法中,我們可以對比修改前後的 props 的值,來做相應的處理,比如呼叫 setstate() 方法來設定 state。不過官方顯然不建議我們這樣做,而在建議我們在componentdidmount()方法中來處理。

另外,如果父元件的行為導致元件重新渲染,也會觸發這個方法執行,即使元件的屬性值並沒有改變。

componentwillreceiveprops() 之後的流程與 state 更改的流程一致,所以我們統一在下面來討論這個過程。

state 是元件的內生狀態。這讓元件看上去像是乙個狀態機,在不同的狀態下,顯示不同的內容。

constructor(props) ;

}複製**

這裡有幾點需要注意:

在 constructor() 構造器中必須首先呼叫super(props),否則在構造器中 this.props 是未定義的,可能會引發 bug;

constructor() 是唯一直接設定 this.state 的地方,其它地方都通過 setstate() 方法來設定 state;

在 constructor() 中不能使用 setstate() 方法來設定 state;

盡量避免將 props 的值拷貝到 state 中,一方面是沒必要,另一方面是 props 修改時,對應 state 的值並不會同步修改(反模式);

state 值的修改同樣會引發元件的重新渲染,這個過程中呼叫的 hook 方法和 props 的變更一樣。在這個過程中,會呼叫以下幾個方法:

shouldcomponentupdate(nextprops, nextstate)

componentwillupdate(nextprops, nextstate)

render()

componentdidupdate(prevprops, prevstate, snapshot)

shouldcomponentupdate(nextprops, nextstate)方法中,我們可以根據 nextprops 或 nextstate 的值來確定是否需要重新渲染元件。預設是返回 true,如果返回 false,則後續流程會被中斷。不過,這個方法的用途更多的是在於效能的優化,以減少不必要的渲染,而不是去依賴它來「阻止」渲染。

componentwillupdate(nextprops, nextstate)是在即將更新元件之前的操作。這個方法在當前最新版本中同樣被重新命名為unsafe_componentwillupdate(nextprops, nextstate)。在這個方法中,我們不能去呼叫 setstate 方法,或者做其它可能會引起元件重新渲染的操作。

componentdidupdate(prevprops, prevstate, snapshot)方法會在元件重新渲染完成之後呼叫。我們可以看到這時引數名已變成prevpropsprevstate,儲存的是更新之前的 props 和 state。在這個方法中,可以去執行 dom 操作,也可以去做網路請求等操作。同樣,在這個方法中可以呼叫 setstate() 方法,不過一定需要有乙個條件語句來控制 setstate() 方法的呼叫,否則會導致無限迴圈。

實際上,在官方的最新文件中,有幾個生命週期方法已被標記為 unsafe

這幾個方法對應的無字首方法如下:

這幾個方法在v17之前還會繼續存在。不建議使用這幾個方法是因為在這幾個方法中做一些 side effect 時(如 setstate() )時,會引發一些意想不到的問題。

在省去這幾個方法後,生命週期的流程圖就變成如下:

實際上在這個流程中我們可以看到下面這個方法:

static getderivedstatefromprops(props, state)

複製**

這是在 react 16.3 新加入的方法,主要是為了避免在 unsafe_componentwillreceiveprops 中使用 setstate() 而產生的***。關於這個方法,需要注意幾點:

這裡我們主要介紹了 props 和 state 與元件生命週期的關聯。需要知道的就是這兩個物件中的值發生改變時會引發元件的重新渲染,然後會執行一些 hook 方法。特別需要注意的是在這些 hook 方法中,我們需要正確的使用 setstate() 方法,否則會導致一些未知的問題。

官方文件:react.component

React 狀態管理 狀態與生命週期

在 react 狀態管理 從 props 和 state 說起 一篇中,我們介紹了乙個 react 元件狀態管理的基礎 props 和 state,以及這兩個物件對 react 元件渲染的影響。在這一篇裡,我們來看看這兩個物件在元件的生命週期中,是如何與元件相互作用的。生命週期是乙個很寬泛的概念。小...

React狀態管理

狀態管理 為什麼react要使用狀態管理 那麼狀態管理做了什麼呢?三者都是架構思維,react只是它的乙個組成部分 flux flux它是一種架構思維,和mvc是同乙個級別的 要求 說明 redux 重點 redux可以說是flux 函式式程式設計的乙個結合體 說明 要求 mobx flux這個架構...

React 狀態管理之Redux

flux vuex vue react redux react state 狀態收集 更新內部state狀態,更新component 1.建立預設狀態 一般const or let乙個物件 const defaultstate 2.建立 reducer 純函式 函式必須有返回值 let reduce...