本篇將介紹 React 組件的API,其中主要的幾個API我們在第一篇的時候便已介紹過,這里可以做個溫故知新。
本篇的代碼你也可以在我的Github上獲取到。
setState
參數: nextState(object), [callback(function)]
設置 nextState 的某個鍵(屬性)值(別忘了我們可以在 shouldComponentUpdate 方法中獲取到 nextState 的值來跟當前的 this.state 進行對比),然后下一次 EventLoop 時 this.state 的對應鍵就會被更新為該設定的值。
通常我們如果希望在某個事件或某個回調中來重新渲染組件(觸發UI更新內容),setState 是一個最常用的觸發方法,因為我們把UI內容跟state狀態直接(或者通過某些條件)綁定在了一起,一旦state發生改變並觸動了綁定的邏輯,那么UI內容自然也會跟着變動:
var Component1 = React.createClass({ getInitialState: function() { return { isClick: !1 } }, componentDidUpdate: function(){ console.log('componentDidUpdate') }, clickCb: function() { this.setState({ isClick : !0 }, function(){ console.log(this.state.isClick) }) }, render: function() { return (<div onClick={this.clickCb}> isClick:{this.state.isClick ? 'yes' : 'nope'} </div>) } }); var div = document.getElementById('a'); React.render( <Component1 />, div );
如上我們通過 state.isClick 來決定div內要顯示的內容,而我們點擊div時會改變 state.isClick 的狀態,從而觸發綁定條件更改了div中的內容。
注意這段代碼里我們使用了 componentDidUpdate 方法,如第二篇文章中所介紹的,它在組件重新渲染后會立即觸發。我們點擊 div 之后發現打印順序是這樣的:
即我們在 setState 方法中所定義的回調,它是在組件重新渲染之后才執行的,而不是在我們變更了 nextState 的值之后就立即觸發。
replaceState
參數: nextState(object), [callback(function)]
類似於 setState(),但是刪除之前所有已存在的 state 鍵(key),這些鍵都不在 nextState 中。
這句話怎么理解呢?我們看這個例子:
var Component1 = React.createClass({ getInitialState: function() { return { isClick: !1, abc: 1 //注意這里我們初始化了一個 state.abc } }, clickCb: function() { this.replaceState({ isClick : !0 }, function(){ console.log(this.state) }) }, render: function() { return (<div onClick={this.clickCb}> isClick:{this.state.isClick ? 'yes' : 'nope'} </div>) } }); var div = document.getElementById('a'); React.render( <Component1 />, div );
注意我們在 getInitialState 里還額外定義了一個 abc 的 state 屬性,但在 replaceState 后再試着打印 this.state,會發現這個 state.abc 已經被刪除了(如果換成 setState 則不會被刪除)。
所以顧名思義,replaceState 就是一個徹底更換掉 state 的方法,尋常使用的時候需要小心使用,避免刪掉一些重要的state屬性。
forceUpdate
參數: [callback(function)]
顧名思義就是在任何調用的時刻強制渲染組件,例如即使 shouldComponentUpdate 返回了false:
var Component1 = React.createClass({ shouldComponentUpdate: function(nextProps, nextState){ console.log( this.state, nextState ); this.forceUpdate(function(){ console.log('強制渲染完成') }); //強制渲染,去掉這行則不會渲染 return false; }, componentDidUpdate: function(){ console.log('componentDidUpdate') }, getInitialState: function() { return { isClick: !1 } }, clickCb: function() { this.setState({ isClick : !this.state.isClick }) }, render: function() { return (<div onClick={this.clickCb}> isClick:{this.state.isClick ? 'yes' : 'nope'} </div>) } }); var div = document.getElementById('a'); var c1 = React.render( <Component1 />, div );
注意該方法的回調,也是在重新渲染之后才執行的。
另一個使用 forceUpdate 的場景可以是,我們不以 props 或 state 來作為觸發渲染的條件,例如使用了一個變量來作為UI內容,在該變量的值改變了且我們希望觸發渲染時,可以使用該方法,當然這種形式是不推薦的。
getDOMNode()
返回組件/ReactElement掛載到頁面上所對應的DOM元素:
var Component1 = React.createClass({ getInitialState: function() { return { isClick: !1 } }, clickCb: function() { this.setState({ isClick : !0 }, function(){ console.log(this.state.isClick) }) }, render: function() { return (<div onClick={this.clickCb}> isClick:{this.state.isClick ? 'yes' : 'nope'} </div>) } }); var div = document.getElementById('a'); var c = React.render( <Component1 />, div ); console.log(c.getDOMNode())
打印結果:
另外,若 render 返回 null 或者 false 的時候,this.getDOMNode() 將返回 null。
isMounted()
返回一個 Boolean 值,如果組件掛載到了 DOM 中,isMounted() 返回 true。
其適用於異步請求的情景下:
var Component1 = React.createClass({ getInitialState: function() { return { content: 'hello' } }, componentWillMount: function () { doSomething(props).then(function (content) { if (this.isMounted()) { this.setState({content: content}); } }.bind(this)); }, render: function() { if(this.state.isClick){ return (<div> content:{this.state.content} </div>) } else { return false; } } }); var div = document.getElementById('a'); var c = React.render( <Component1 />, div );
如上代碼,我們在 componentWillMount 的時候執行一個異步請求 doSomething,在其獲取到服務器數據的時候修改 state 的值,前提是組件已經掛載到頁面上。
如果該異步請求完成得很快,我們獲取到新content時候組件可能還在處於掛載中(mounting)的過程,那么 state 則保持不變(因為此時 isMounted() 將返回false )。
setProps
參數: nextProps(object), [callback(function)]
跟 setState 類似,不過修改的是 props 罷了:
var Component1 = React.createClass({ clickCb: function() { this.setProps({ name : 'cnBlog' }, function(){ console.log(this.props) }) }, render: function() { return (<div onClick={this.clickCb}> {this.props.sayhi || 'www.'} {this.props.name || 'nothing'} </div>) } }); var div = document.getElementById('a'); React.render( <Component1 name="VaJoy" sayhi="Hello " />, div );
replaceProps
參數: nextProps(object), [callback(function)]
類似於 setProps,會替換掉現有的 props 的鍵,我們依舊使用上一段代碼,不過把 setProps 換成 replaceProps:
var Component1 = React.createClass({ clickCb: function() { this.replaceProps({ name : 'cnBlog' }, function(){ console.log(this.props) }) }, render: function() { return (<div onClick={this.clickCb}> {this.props.sayhi || 'www.'} {this.props.name || 'nothing'} </div>) } }); var div = document.getElementById('a'); React.render( <Component1 name="VaJoy" sayhi="Hello " />, div );
我們這時再點擊組件,會發現 props.sayHi 已被刪除了:
Refs
事實上這個不屬於組件的方法,但也是在組件中常用的一個小技巧,故在這里做介紹。
我們在前面提到,可以使用 ReactClass.getDOMNode() 的方法來獲取到組件渲染在頁面上的DOM節點,但是如果我們希望獲取到的,是組件中的某個DOM元素呢?
這時候我們可以使用定義 refs 的形式,來方便我們獲取對應的元素:
var Component1 = React.createClass({ clickCb: function(e) { if(e.target === this.refs.li2.getDOMNode()){ alert('你點到第二個LI了') } }, render: function() { return (<ul onClick={this.clickCb}> <li>1</li> <li ref="li2">2</li> <li>3</li> </ul>) } }); var div = document.getElementById('a'); React.render( <Component1 />, div );
如上我們給組件中的第二個<li>綁定了一個 ref 屬性,值為“li2”,這意味着我們可以在組件中以 this.refs.li2 的形式來獲取到該ReactElement。
然后綁定點擊事件,在點擊的時候判斷被點擊的 li 元素是否等於 this.refs.li2.getDOMNode(),是的話則彈出alert。
官方也給出了一個實用的demo:
var App = React.createClass({ getInitialState: function() { return {userInput: ''}; }, handleChange: function(e) { this.setState({userInput: e.target.value}); }, clearAndFocusInput: function() { // Clear the input this.setState({userInput: ''}, function() { // 組件重繪后會立即執行這句代碼: this.refs.theInput.getDOMNode().focus(); // input成功聚焦(focus) }); }, render: function() { return ( <div> <div onClick={this.clearAndFocusInput}> Click to Focus and Reset </div> <input ref="theInput" //我們可以在組件里以 this.refs.theInput 獲取到它 value={this.state.userInput} onChange={this.handleChange} /> </div> ); } });
到此位置我們便基本入門了 React 的大部分主要的API,后續我們將以項目實踐的形式來進一步學習React。
共勉~!