從你的 render 方法中返回你的 UI 結(jié)構(gòu)后,你會(huì)發(fā)現(xiàn)你想要“伸手”調(diào)用從 render 返回的組件實(shí)例的方法。通常來(lái)說(shuō),這樣做對(duì)于通過(guò)你的應(yīng)用程序制作數(shù)據(jù)流是沒(méi)有必要的,因?yàn)?Reactive 數(shù)據(jù)流總是確保最新的 props 被發(fā)送到由 render() 輸出的每個(gè)孩子中。但是在一些情況下,它仍然有可能是必要或有益的。
考慮這樣一種情況,當(dāng)你在把一個(gè) <input / > 元素(存在于你的實(shí)例 sub-hierarchy 中)的值更新為一個(gè)空字符串后 ,想告訴它聚焦。
var App = React.createClass({
getInitialState: function() {
return {userInput: ''};
},
handleChange: function(e) {
this.setState({userInput: e.target.value});
},
clearAndFocusInput: function() {
this.setState({userInput: ''}); // Clear the input
// We wish to focus the <input /> now!
},
render: function() {
return (
<div>
<div onClick={this.clearAndFocusInput}>
Click to Focus and Reset
</div>
<input
value={this.state.userInput}
onChange={this.handleChange}
/>
</div>
);
}
});
注意,在本例中,我們想要“告訴”輸入一些東西——這些東西是它不能從道具中推斷出的。在這個(gè)例子中,我們想要“告訴”它,現(xiàn)在它應(yīng)該聚焦。然而,也有一些挑戰(zhàn)。從 render() 返回的不是你 “子”組件的實(shí)際組成,它僅僅是在一個(gè)特定的實(shí)例中的子組件的描述——如果你愿意的話可以是一個(gè)快照。
注意:
記住,從
render()返回來(lái)的不是你實(shí)際繪制的子組件的實(shí)例。從render()返回來(lái)的僅僅是一個(gè)特定的時(shí)刻在你組成部分的 sub-hierarchy 中的子組件實(shí)例的描述。
這意味著你不應(yīng)該“持有”從 render() 返回來(lái)的東西,并且指望它有任何的意義。
// counterexample: DO NOT DO THIS!
render: function() {
var myInput = <input />; // I'm going to try to call methods on this
this.rememberThisInput = myInput; // input at some point in the future! YAY!
return (
<div>
<div>...</div>
{myInput}
</div>
);
}
在這個(gè)反例中,<input/ > 僅僅是 <input/ > 的描述。這個(gè)描述是用來(lái)為 <input/ > 創(chuàng)建一個(gè)真正的 支持實(shí)例。
那么, 我們?cè)趺丛L問(wèn) input的 真正的 支持實(shí)例呢?
React 支持一個(gè)非常特殊的屬性,你可以附加到任何從 render() 輸出的組件中。這個(gè)特殊的屬性允許你涉及相應(yīng)的任何從 render() 返回的支持實(shí)例。它總是保證成為適當(dāng)?shù)膶?shí)例,在任何時(shí)候。
這個(gè)非常簡(jiǎn)單:
render 返回的東西分配 ref 屬性,如:<input ref="myInput" />
this.refs 訪問(wèn) backing instance,如:this.refs.myInput
你可以通過(guò)調(diào)用 React.findDOMNode(this.refs.myInput) 直接訪問(wèn)組件的 DOM 節(jié)點(diǎn)。
ref 屬性可以是一個(gè)回調(diào)函數(shù),而不是一個(gè)名字。這個(gè)回調(diào)函數(shù)在組件安裝后立即執(zhí)行。被引用的組件作為一個(gè)參數(shù)傳遞,且回調(diào)函數(shù)可以立即使用這個(gè)組件,或保存供以后使用(或?qū)崿F(xiàn)這兩種行為)。
它與把 ref 屬性分配給從 render 返回來(lái)的東西一樣簡(jiǎn)單,如:
<input ref={ function(component){ React.findDOMNode(component).focus();} } />
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 code executes after the component is re-rendered
React.findDOMNode(this.refs.theInput).focus(); // Boom! Focused!
});
},
render: function() {
return (
<div>
<div onClick={this.clearAndFocusInput}>
Click to Focus and Reset
</div>
<input
ref="theInput"
value={this.state.userInput}
onChange={this.handleChange}
/>
</div>
);
}
});
在這個(gè)例子中,render 函數(shù)返回 <input/ > 實(shí)例的描述。但真正的實(shí)例是通過(guò) this.refs.theInput 訪問(wèn)的。只要帶有 ref =“theInput” 的子組件從 render 返回,this.refs.theInput 就會(huì)訪問(wèn)適當(dāng)?shù)膶?shí)例。這甚至能在更高的級(jí)別(non-DOM)組件中實(shí)現(xiàn),如 <Typeahead ref = " myTypeahead " / >。
向一個(gè)特定的子實(shí)例發(fā)送消息,Refs 是一個(gè)很好的方式,而通過(guò)流動(dòng)式接收 Reactive 的 props 和 state 的方式可能是不方便的。然而,對(duì)于你的應(yīng)用程序中的流動(dòng)數(shù)據(jù)來(lái)說(shuō),refs 應(yīng)該不是你的首選抽象特性。默認(rèn)情況下,為用例使用 Reactive 數(shù)據(jù)流并保存 refs 本來(lái)就是無(wú)功無(wú)過(guò)的。
this.refs.myTypeahead.reset())調(diào)用這些公共方法。<input/ >,并通過(guò) React.findDOMNode(this.refs.myInput) 訪問(wèn)它的底層 DOM 節(jié)點(diǎn)。Refs 是可行的可靠的方法之一。ref =“myRefString”,你必須使用 this.refs['myRefString'] 來(lái)訪問(wèn)。state 應(yīng)該屬于組件層次結(jié)構(gòu)的什么位置。通常情況下,你會(huì)清楚地發(fā)現(xiàn),“擁有”那個(gè) state 的適當(dāng)?shù)奈恢檬歉叩膶哟谓Y(jié)構(gòu)中。把 state 放置在那里通??梢韵魏蜗胍褂?ref 來(lái)“讓事情發(fā)生”的現(xiàn)象——相反,數(shù)據(jù)流通常會(huì)實(shí)現(xiàn)你的目標(biāo)。