【重點】React.Component用法
元件(Components)
允許您將UI拆分為獨立的可重用的部分,並單獨的考慮每個部分。
總覽
React.Component
是一個抽象基類。這意味著直接引用React.Component
是毫無意義的。你可以實現一個它的子類,並且至少定義一個render()
方法即可使用。
你可以使用ES6中class
定義一個React元件:
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}</hr>;
}
}
如果你還沒有使用ES6,你可以使用React.createClass()
元件的生命週期方法
每個元件都有幾個『生命週期方法』,您可以重寫這些方法,已便在React執行過程中的指定時間執行自己的程式碼。字首為Will
的生命週期方法會在在一些事情發生之前被呼叫,帶有Did
字首的方法在某些事情發生之後被呼叫。
Mounting(載入元件)
當建立元件的例項並將其插入DOM時,會依次呼叫這些方法:
-
constructor()
-
componentWillMount()
-
render()
-
componentDidMount()
Updating(更新狀態)
更新可以由prop或者state的改變引起。在重新渲染元件時依次呼叫這些方法:
-
componentWillReceiveProps()
-
shouldComponentUpdate()
-
componentWillUpdate()
-
render()
-
componentDidUpdate()
Unmounting(解除安裝元件)
當從DOM中刪除元件時,將呼叫此方法:
-
componentWillUnmount()
其他API
每個元件還提供了一些其他API:
-
setState()
-
forceUpdate()
元件屬性
-
defaultProps
-
displayName
-
propTypes
例項內部屬性
-
props
-
state
使用方法
render()
render() {
// return React Elements
}
注意:render()
方法是必須寫的。
當這個方法被呼叫時,它會檢測this.props
和this.state
並返回一個React元素。此元素可以是本地DOM元件的形式,例如<div/>
,也可以是您自己定義的一個複合元件。
你也可以返回null
或false
來表示你不想做任何渲染操作。當返回null
或false
時,ReactDOM.findDOMNode(this)
將返回null
。
render()
方法應該是純的(pure
function
,見函數語言程式設計),這意味著它並不會修改元件state,每次呼叫它時都會返回相同的結果,它不會直接與瀏覽器互動。如果您需要與瀏覽器直接互動,請改用componentDidMount()
方法或者其他生命週期方法來執行你的邏輯。保持render()
的純
可以讓元件更容易去思考自己應該做什麼。
提示
如果shouldComponentUpdate()
返回false
,那麼render()
不會被執行。
constructor()
constructor(props)
在裝載元件(mounting)之前呼叫會React元件的建構函式。當實現React.Component
子類的建構函式時,應該在任何其他語句之前呼叫super(props)
。否則,this.props
將在建構函式中未定義,這可能導致錯誤。
建構函式是初始化state的標準位置。如果不初始化state,並且不繫結元件內部方法的this指向,則不需要為React元件實現建構函式。
如果你知道你在做什麼的話,你可以根據props來初始化state。這裡有一個有效的React.Component
子類建構函式的例子:
constructor(props) {
super(props);
this.state = {
color: props.initialColor
};
}
注意這種模式,因為它會將props複製一份在state中,這就可能導致一個意外的bug。所以不應該將props複製到state中。相反,你需要使用提升state
的技巧,該技巧我們在前面的文章提到過。
如果你使用props複製到state中,你還需要實現componentWillReceiveProps(nextProps)
來保持state是最新的。這個時候使用提升state的方法反而會更容易,也能產生更少的bug。
componentWillMount()
componentWillMount()
componentWillMount()
是在裝載(mounting)發生之前被呼叫。它在render()
之前呼叫,所以在此方法中的設定state不會造成重新渲染。另外,應該避免在此方法中引入有任何副作用的東西(見函數語言程式設計)
。
在伺服器渲染上這是唯一一個呼叫的生命週期鉤子函式。一般來說,我們建議使用constructor()
。
componentDidMount()
componentDidMount()
componentDidMount()
在元件裝載到DOM後立即呼叫。如果需要進行DOM節點的初始化則應該在這裡來執行該邏輯。如果需要從遠端端點載入資料(ajax
),那麼這是處理網路請求的最好地方。在此方法中設定state會去重新渲染DOM。
componentWillReceiveProps()
componentWillReceiveProps(nextProps)
componentWillReceiveProps()
在安裝好的元件接收新props之前被呼叫。 如果你需要更新state用來響應props的更改(例如,重置它),你可以在此方法中比較this.props
和nextProps
並使用this.setState()
來替換並重置state。
注意,即使props沒有改變,React
也可以呼叫這個方法,因此如果你只想處理props改變的情況,請確保比較當前值和下一個值是否不同。
當父元件引起你的元件重新渲染時,就有可能會發生這種情況。
如果你只是呼叫this.setState()
,那麼componentWillReceiveProps()
不會被呼叫。
shouldComponentUpdate()
shouldComponentUpdate(nextProps, netState)
使用shouldComponentUpdate()
讓React知道元件是否受當前state或props變化的影響。 預設行為是在每次state更改時都會去重新渲染DOM,在絕大多數情況下,你應該依賴於這個預設行為。
當接收到新的props或state時,shouldComponentUpdate()
在渲染之前被呼叫。 預設為true
對於初始渲染或使用forceUpdate()
,不呼叫此方法。
返回false
不會阻止子元件在state更改時重新渲染。
目前,如果shouldComponentUpdate()
返回false
,那麼將不會呼叫componentWillUpdate()
,render()
和componentDidUpdate()
。
注意,在將來React可以將shouldComponentUpdate()
作為提示而不是嚴格的操作指令
,返回false
仍然可能導致元件的重新渲染。
如果你確定某些元件在某些操作時有點緩慢,你可以讓它繼承React.PureComponent
,而不是繼承React.Component
。
React.PureComponent
實現了props
和state
進行淺比較的shouldComponentUpdate()
方法。
如果你確定想人肉處理這個淺比較
操作,你可以自己在這個函式中比較this.props
和nextProps
、this.state
和nextState
是否相同。相同返回false
,不同返回true
,那麼React就會根據返回值來確認是否跳過本次DOM渲染。
componentWilUpdate()
componentWillUpdate(nextProps, nextState)
當元件在收到新的props或state時,componentWillUpdate()
在渲染之前會立即呼叫這個方法。 使用這個方法來判斷是非需要重新渲染DOM。
第一次渲染DOM不呼叫此方法。
注意,this.setState()
不會呼叫此方法。 如果你需要根據state和props來進行重新渲染DOM,請改用componentWillReceiveProps()
。
note
如果shouldComponentUpdate()
返回false
,則不會呼叫componentWillUpdate()
。
componentDidUpdate()
componentDidUpdate(prevProps, prevState)
componentDidUpdate()
在重新渲染DOM之後被呼叫。 第一次渲染不呼叫此方法。
當元件已經重新渲染後,此方法是一個執行DOM操作的好機會,同時也是一個處理網路請求的好地方,前提是你需要比較當前props與之前的props是否相同(例如,如果props沒有改變,那麼可能不需要進行網路請求)。
note
如果shouldComponentUpdate()
返回false
,則不會呼叫componentDidUpdate()
。
componentWillUnmount()
componentWillUnmount()
componentWillUnmount()
在元件被解除安裝和銷燬之前立即被呼叫。 此方法可以執行任何有必要的清理工作,例如清理計時器,取消網路請求或清理在componentDidMount()
中建立的DOM元素。
setState()
setState(nextState, callback)
將nextState和當前state進行淺合併。 這是用於從事件處理函式和伺服器請求回撥中觸發UI重新渲染的主要方法。
第一個引數可以是一個物件(包含一個或多個要更新的state屬性),也可以是返回將要引起重新渲染的物件(state和props)。
這裡有一個簡單的用法:
this.setState({myKey: 'my new value'});
它也可以傳入一個帶有引數的函式function(state,props)=> newState
。 例如,假設我們想要當前state中的myInteger加上props.step:
this.setState(prevState, props) => {
return {myInteger: prevState.myInteger + props.step};
}
第二種引數是回撥函式,一旦setState完成並且元件被重新渲染,它就會被執行。 通常我們建議使用componentDidUpdate()
代替這樣的邏輯。
setState()
不會立即改變this.state
,但會建立並掛起state的修改。
所以在呼叫此方法中訪問this.state
可能會返回現有值。
不能保證對setState
的所以呼叫都是同步操作,因為這樣做是為了將多次state修改合併為一次以便提高效能。
setState()
總會重新渲染DOM,除非shouldComponentUpdate()
回false。
如果你正在使用可突變物件,並且無法在shouldComponentUpdate()
實現條件渲染邏輯,則只有當新state與先前state不同時呼叫setState()
才能避免不必要的重新渲染。
forceUpdate()
component.forceUpdate(callback)
預設情況下,當元件的state或props改變時,元件將重新渲染。 如果你的render()
方法依賴於一些其他資料,你可以告訴React元件需要通過呼叫forceUpdate()
來重新渲染。
呼叫forceUpdate()
會導致在元件上呼叫render()
,跳過shouldComponentUpdate()
這將觸發子元件的正常生命週期方法,包括每個子元件的shouldComponentUpdate()
方法。
如果標記更改,React仍將更新DOM。
通常你應該儘量避免forceUpdate()
的所有使用,並且只能從render()
中的this.props
和this.state
中讀取。
類屬性
defaultProps
defaultProps
是類元件本身的屬性,用來設定類元件的預設props。 可以用來給未傳入值的props設定預設值。 例如:
class CustomButton extends React.Component {
// ...
}
CustomButton.defaultProps = {
color: 'blue';
}
如果props.color
沒有定義,就是將它設定為預設值blue
:
render() {
return <CustomButton />; // props.color will be set to blue
}
如果props.color
被設定為null
,那麼它將會被重新賦值為null:
render() {
return <CustomButton color={null} />; // props.color will remain null
}
displayName
displayName
字串用於除錯訊息。 JSX
自動設定此值;
propTypes
propTypes
也是類元件本身上的一個屬性,用來規範props應該是什麼型別。 它是從props的名稱到React.PropTypes
中定義的型別的對映。
在開發模式下,當為prop設定一個不是指定格式的無效值時,會在JavaScript控制檯中顯示警告資訊。 在生產模式下,為了提高效率,不會進行propTypes
檢查。
例如,此程式碼確保顏色prop是一個字串:
class CustomButton extends React.Component {
// ...
}
CustomButton.propTypes = {
color: React.PropTypes.string
};
我們建議儘可能使用Flow
,以便在編譯時進行型別檢查,而不是在執行時進行型別檢查。 Flow
在React中內建支援,因此可以輕鬆地在React應用程式上執行靜態分析。
// @flow
function foo(x) {
return x * 10;
}
foo('Hello, world!');
// @flow
function bar(x): string {
return x.length;
}
bar('Hello, world!');
例項屬性
props
this.props
包含由此元件的呼叫者定義的props
。
特別地,this.props.children
是一個特殊的props,通常由JSX表示式中的子標籤而不是標籤本身定義。
state
state包含特定於此元件的資料,可能隨時間更改。 state是使用者定義的,它應該是純JavaScript物件。
如果你不在render()
中使用它,它不應該設定state。 例如,您可以將定時器ID直接放在例項上。
永遠不要直接改變this.state
,因為呼叫setState()
之後可以替換你所做的各種變化,
通常應該把this.state
看作是不可變的。