從你的 render 方法中返回你的 UI 結構后,你會發(fā)現(xiàn)你想要“伸手”調用從 render 返回的組件實例的方法。通常來說,這樣做對于通過你的應用程序制作數(shù)據(jù)流是沒有必要的,因為 Reactive 數(shù)據(jù)流總是確保最新的 props
被發(fā)送到由 render()
輸出的每個孩子中。但是在一些情況下,它仍然有可能是必要或有益的。
考慮這樣一種情況,當你在把一個 <input / >
元素(存在于你的實例 sub-hierarchy 中)的值更新為一個空字符串后
,想告訴它聚焦。
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>
);
}
});
注意,在本例中,我們想要“告訴”輸入一些東西——這些東西是它不能從道具中推斷出的。在這個例子中,我們想要“告訴”它,現(xiàn)在它應該聚焦。然而,也有一些挑戰(zhàn)。從 render()
返回的不是你 “子”組件的實際組成,它僅僅是在一個特定的實例中的子組件的描述——如果你愿意的話可以是一個快照。
注意:
記住,從
render()
返回來的不是你實際繪制的子組件的實例。從render()
返回來的僅僅是一個特定的時刻在你組成部分的 sub-hierarchy 中的子組件實例的描述。
這意味著你不應該“持有”從 render()
返回來的東西,并且指望它有任何的意義。
// 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>
);
}
在這個反例中,<input/ >
僅僅是 <input/ >
的描述。這個描述是用來為 <input/ >
創(chuàng)建一個真正的 支持實例。
那么, 我們怎么訪問 input的 真正的 支持實例呢?
React 支持一個非常特殊的屬性,你可以附加到任何從 render()
輸出的組件中。這個特殊的屬性允許你涉及相應的任何從 render()
返回的支持實例。它總是保證成為適當?shù)膶嵗?,在任何時候。
這個非常簡單:
render
返回的東西分配 ref
屬性,如:<input ref="myInput" />
this.refs
訪問 backing instance,如:this.refs.myInput
你可以通過調用 React.findDOMNode(this.refs.myInput)
直接訪問組件的 DOM 節(jié)點。
ref
屬性可以是一個回調函數(shù),而不是一個名字。這個回調函數(shù)在組件安裝后立即執(zhí)行。被引用的組件作為一個參數(shù)傳遞,且回調函數(shù)可以立即使用這個組件,或保存供以后使用(或實現(xiàn)這兩種行為)。
它與把 ref
屬性分配給從 render
返回來的東西一樣簡單,如:
<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>
);
}
});
在這個例子中,render 函數(shù)返回 <input/ >
實例的描述。但真正的實例是通過 this.refs.theInput
訪問的。只要帶有 ref =“theInput”
的子組件從 render 返回,this.refs.theInput
就會訪問適當?shù)膶嵗_@甚至能在更高的級別(non-DOM)組件中實現(xiàn),如 <Typeahead ref = " myTypeahead " / >
。
向一個特定的子實例發(fā)送消息,Refs 是一個很好的方式,而通過流動式接收 Reactive 的 props
和 state
的方式可能是不方便的。然而,對于你的應用程序中的流動數(shù)據(jù)來說,refs 應該不是你的首選抽象特性。默認情況下,為用例使用 Reactive 數(shù)據(jù)流并保存 ref
s 本來就是無功無過的。
this.refs.myTypeahead.reset()
)調用這些公共方法。<input/ >
,并通過 React.findDOMNode(this.refs.myInput)
訪問它的底層 DOM 節(jié)點。Refs 是可行的可靠的方法之一。ref =“myRefString”
,你必須使用 this.refs['myRefString']
來訪問。state
應該屬于組件層次結構的什么位置。通常情況下,你會清楚地發(fā)現(xiàn),“擁有”那個 state 的適當?shù)奈恢檬歉叩膶哟谓Y構中。把 state 放置在那里通??梢韵魏蜗胍褂?ref
來“讓事情發(fā)生”的現(xiàn)象——相反,數(shù)據(jù)流通常會實現(xiàn)你的目標。