書籍完整目錄
1.4 React 組件生命週期
官方文檔
1.4.1 組件
React 中組件有自己的生命週期方法,簡單理解可以為組件從 出生(實例化) -> 激活 -> 銷燬 生命週期 hook。通過這些 hook 方法可以自定義組件的特性。 除此之外,還可以設置一些額外的規格配置。
這些生命週期方法都可以在調用 React.createClass 的參數對象中傳入, 我們已經使用過了一些方法:
-
render
-
getInitialState
-
getDefaultProps
-
propTypes
1.4.2 mixins
類型: array mixins
mixins 可以理解為 React 的插件列表,通過這種模式在不同組件之間共享方法數據或者行為只需共享 mixin 就行,mixins 內定義的生命週期方法在組件的生命週期內都會被調用。
可能的一些疑問:
-
Q1. 如果組件已經定義了某個生命週期方法, mixin 內也定義了該方法,那麼 mixin 內會被調用還是 組件的會被調用?
-
Q2. 多個插件都定義了相同生命週期的方法呢?
-
Q3. 那如果多個插件定義了 getInitialState 這種配置方法呢,有何影響?
插件模式並非繼承的模式,對於問題 1、2 的答案是一樣的,都會被調用,調用順序為 mixins 數組中的順序。
-
A1: 都會被調用
-
A2: 都會被調用
-
A3: React 會對返回結果做智能的合併,所有插件的 getInitialState 都會生效,前提條件是它們返回的字段不衝突,如果發生字段衝突,React 會提示報錯。 同理如果是非 組件的規格方法,出於共享目的的一些方法在多個 mixin 中也不能衝突。
eg:
var MyMixin1 = {
componentDidMount: function() {
console.log('auto do something when component did mount');
}
};
var MyMixin2 = {
someMethod: function() {
console.log('doSomething');
}
};
var MyComponnet = React.createClass({
mixins: [MyMixin1, MyMixin2],
componentDidMount: function() {
// 調用 mixin1 共享的方法
this.someMethod();
}
});
更多 mixins 的使用會在第三章中講解。
1.4.3 statics
類型: object statics
statics 可以定義組件的類方法
eg:
var MyComponent = React.createClass({
statics: {
customMethod: function(foo) {
return foo === 'bar';
}
}
});
MyComponent.customMethod('bar'); // true
React 的組件是 OOP 的思維,MyComponent 是一個 class,class 分為類方法和實例方法,實例方法可以訪問 this, 然而類方法不能,所以我們不能在 Class 中返回狀態或者屬性。
1.4.4 displayName
類型: string displayName
為了顯示調試信息,每個組件都會有一個名稱,JSX 在轉為 JS 的時候自動的設置 displayName, 如下:
// Input (JSX):
var MyComponent = React.createClass({ });
// Output (JS):
var MyComponent = React.createClass({displayName: "MyComponent", });
當然我們也可以自定義 displayName
1.4.5 生命週期方法
下圖描述了整個組件的生命週期,包含的主要幾種情況:
-
組件被實例化的時候
-
組件屬性改變的時候
-
組件狀態被改變的時候
-
組件被銷燬的時候
1.4.6 componentWillMount
void componentWillMount()
條件:第一次渲染階段在調用 render 方法前會被調用
作用:該方法在整個組件生命週期只會被調用一次,所以可以利用該方法做一些組件內部的初始化工作
1.4.7 componentDidMount
void componentDidMount()
條件:第一次渲染成功過後,組件對應的 DOM 已經添加到頁面後調用
作用:這個階段表示組件對應的 DOM 已經存在,我們可以在這個時候做一些依賴 DOM 的操作或者其他的一些如請求數據,和第三方庫整合的操作。如果嵌套了子組件,子組件會比父組件優先渲染,所以這個時候可以獲取子組件對應的 DOM。
1.4.8 componentWillReceiveProps(newProps)
void componentWillReceiveProps(
object nextProps
)
條件: 當組件獲取新屬性的時候,第一次渲染不會調用
用處: 這個時候可以根據新的屬性來修改組件狀態
eg:
componentWillReceiveProps: function(nextProps) {
this.setState({
likesIncreasing: nextProps.likeCount > this.props.likeCount
});
}
注意: 這個時候雖説是獲取新屬性,但並不能確定屬性一定改變了,例如一個組件被多次渲染到 DOM 中,如下面:
var Component = React.createClass({
componentWillReceiveProps: function(nextProps) {
console.log('componentWillReceiveProps', nextProps.data.bar);
},
rener: function() {
return <div> {this.props.data.bar} </div>
}
});
var container = document.getElementById('container');
var mydata = {bar: 'drinks'};
ReactDOM.render(<Component data={mydata} />, container);
ReactDOM.render(<Component data={mydata} />, container);
ReactDOM.render(<Component data={mydata} />, container);
結果會輸出兩次 componentWillReceiveProps,雖然屬性數據沒有改變,但是仍然會調用 componentWillReceiveProps 方法。
參考 Facebook (A=>B) => (B => A)
1.4.9 shouldComponentUpdate(nextProps, nextState)
boolean shouldComponentUpdate(
object nextProps, object nextState
)
條件: 接收到新屬性或者新狀態的時候在 render 前會被調用(除了調用 forceUpdate 和初始化渲染以外)
用處: 該方法讓我們有機會決定是否重渲染組件,如果返回 false,那麼不會重渲染組件,藉此可以優化應用性能(在組件很多的情況)。
1.4.10 componentWillUpdate
void componentWillUpdate(
object nextProps, object nextState
)
條件:當組件確定要更新,在 render 之前調用
用處:這個時候可以確定一定會更新組件,可以執行更新前的操作
注意:方法中不能使用 setState ,setState 的操作應該在 componentWillReceiveProps 方法中調用
1.4.11 componentDidUpdate
void componentDidUpdate(
object prevProps, object prevState
)
條件:更新被應用到 DOM 之後
用處:可以執行組件更新過後的操作
1.4.12 生命週期與單向數據流
我們知道 React 的核心模式是單向數據流,這不僅僅是對於組件級別的模式,在組件內部 的生命週期中也是應該符合單向數據的模式。數據從組件的屬性流入,再結合組件的狀態,流入生命週期方法,直到渲染結束這都應該是一個單向的過程,其間不能隨意改變組件的狀態。
1.4.13 實例練習:通過 mixin 打印出組件生命週期的執行順序
@todo