1. 程式人生 > >【重點】React.Component用法

【重點】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.propsthis.state並返回一個React元素。此元素可以是本地DOM元件的形式,例如<div/>,也可以是您自己定義的一個複合元件。

你也可以返回nullfalse來表示你不想做任何渲染操作。當返回nullfalse時,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.propsnextProps並使用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實現了propsstate進行淺比較的shouldComponentUpdate()方法。 如果你確定想人肉處理這個淺比較操作,你可以自己在這個函式中比較this.propsnextPropsthis.statenextState是否相同。相同返回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.propsthis.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看作是不可變的。