9.7 KiB
id | title | permalink | prev | next |
---|---|---|---|---|
more-about-refs | 参照についての詳細 | more-about-refs-ja-JP.html | working-with-the-browser-ja-JP.html | tooling-integration-ja-JP.html |
renderメソッドからUIの構成をリターンした後、あなたは「リーチアウト」を見て、renderから返ってきたコンポーネントのインスタンスの上でメソッドを実行するでしょう。多くの場合、アプリケーションにおいて、データフローを作成することは必要ではありません。リアクティブなデータフローは常に最新の props
が render()
から出力されたそれぞれの子要素に送られたことを保証するからです。しかし、まだ必要であったり、利益をもたらすケースもあります。
''
という空の文字列でその値をアップデートした後にフォーカスするということを <input />
要素(インスタンスのサブ階層に存在します)に伝えたいという場合を考えましょう。
var App = React.createClass({
getInitialState: function() {
return {userInput: ''};
},
handleChange: function(e) {
this.setState({userInput: e.target.value});
},
clearAndFocusInput: function() {
this.setState({userInput: ''}); // inputをクリアします
// ここで、<input /> にフォーカスさせたいです!
},
render: function() {
return (
<div>
<div onClick={this.clearAndFocusInput}>
Click to Focus and Reset
</div>
<input
value={this.state.userInput}
onChange={this.handleChange}
/>
</div>
);
}
});
この例では、どうにかしてinputに何かを「伝え」たいということに着目してください。何かというのは、propsから推測できるものではありません。このケースでは、inputが今フォーカスされるべきであるということを「伝え」たいのです。しかし、いくつか問題があります。render()
で返されるものは実際の「子供の」要素ではありません。しかし、特別なインスタンスにおいて子要素の 説明 を行うよりかは、スナップショットを見ていったほうがいいでしょう。
注意:
render()
からリターンされるものは 実際に レンダリングされた子要素のインスタンスではないと覚えておいてください。render()
からリターンされるものは、ある特定の時点においてのコンポーネントの副階層にある単なる子要素のインスタンスの 説明 に過ぎません。
これは、 render()
からリターンされる何かを「保持し続ける」ことはできないことを意味します。そして、それは何かしら意味のあることであると予測できます。
// 反例: このようには記述しないでください!
render: function() {
var myInput = <input />; // このinputの上にあるメソッドを未来のいつかの
this.rememberThisInput = myInput; // タイミングで呼ぼうとしています!いえいっ!
return (
<div>
<div>...</div>
{myInput}
</div>
);
}
この反例では、 <input />
は単に <input />
の 説明 に過ぎず、この説明は <input />
の 現実の バッキングインスタンス を作るために使われます。
では、inputの 現実の バッキングインスタンスについて、どのように話していきましょうか?
参照の文字列属性
Reactは render()
からの出力であるコンポーネントであれば何でもアタッチできるとても特別なプロパティをサポートしています。この特別なプロパティは render()
からのリターンである バッキングインスタンス に対応したものに参照することを許可します。これはどのタイミングにおいても、固有のインスタンスであることを保証されています。
これは以下のように単純です。
- 以下のように、
render
からのリターンであれば何でもref
属性をアサインする。
<input ref="myInput" />
- いくつかの他のコードは(一般的にイベントハンドラのコード)、以下にあるように
this.refs
を通して バッキングインスタンス にアクセスします。
this.refs.myInput
React.findDOMNode(this.refs.myInput)
を呼ぶことで、コンポーネントのDOMノードに直接アクセスできる。
参照のコールバック属性
ref
属性は名前の代わりのコールバック関数になり得ます。このコールバックはコンポーネントがマウントされた直後に実行されます。参照されたコンポーネントはパラメータとして渡され、コールバック関数はコンポーネントを即座に使用するか、または将来使用するために参照を保存します(またはその両方を行います)。
これは、以下のように、 render
でリターンされてきたものに ref
属性をアサインするのと同じくらい簡単です。
<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() {
// inputをクリアする
this.setState({userInput: ''}, function() {
// このコードはコンポーネントが再度レンダリングされた後に実行されます。
React.findDOMNode(this.refs.theInput).focus(); // どーん!フォーカスされました!
});
},
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>
);
}
});
この例では、レンダリング関数は <input />
インスタンスの説明をリターンします。しかし、実際のインスタンスは this.refs.theInput
を通してアクセスされます。 ref="theInput"
を持つ子要素のコンポーネントが render
からリターンされる限り、 this.refs.theInput
は固有のインスタンスにアクセスするでしょう。これは <Typeahead ref="myTypeahead" />
のような高階層の(DOMでない)コンポーネントでも同様に動きます。
要約
リアクティブな props
と state
を通してのストリーミングのアクセスは便利とは言えないため、参照は特定の子要素のインスタンスにメッセージを送るための素晴らしい方法です。しかし、それらは、アプリケーションを通したデータフローの抽象化につながるわけではありません。デフォルトで、リアクティブなデータフローを使ってください。そして、ユースケースのために ref
を保存するのは本質的にはリアクティブではありません。
利益:
- コンポーネントクラス(例えば、Typeaheadのリセットメソッドのようなもの)にパブリックなメソッドを定義できる。また、参照(例えば、
this.refs.myTypeahead.reset()
のように)を通してそれらのパブリックなメソッドを呼べる。 - DOMの計測を行うことは大体いつも
<input />
のような「ネイティブの」コンポーネントやReact.findDOMNode(this.refs.myInput)
を通した根本のDOMノードにアクセスすることを必要とします。参照は、こういったことを期待通りに行う唯一の実用的な方法です。 - 参照は自動的に管理されます!もし子要素が削除されたら、その参照もまた削除されます。メモリに関しての心配は要りません(あなた自身が参照を維持するために何かおかしなことを行っていなければ)。
警告:
- 決して コンポーネントのレンダリングメソッドの中の参照にアクセスしてはいけません。たとえコンポーネントのレンダリングメソッドのいずれかがコールスタックの中のどこかで動いているとしても。
- もしGoogle Closure Compilerのクラッシュからの回復を守りたいなら、文字列として指定されたプロパティとしてアクセスしてはいけないことに気をつけてください。これは、
ref="myRefString"
として参照が定義されている場合は、this.refs['myRefString']
を使ってアクセスしなければいけないことを意味します。 - まだReactでプログラムを書いたことがない場合は、アプリケーションで「何かを起こす」ために参照を使おうとするでしょう。もしそのケースだった場合は、時間をかけて
state
がコンポーネントの階層のどこで保持されるべきか批評的に考えてください。多くの場合は、そのstateを「保持する」ための固有の場所が階層の高いレベルにあることがクリアになります。そのstateをその場所に配置することはよく「何かを起こす」ためにref
を使うための願望を排除します。代わりに、データフローは普通、目標を達成します。