findDOMNode
findDOMNode は、React クラスコンポーネントインスタンスに対応するブラウザ DOM ノードを見つけます。
const domNode = findDOMNode(componentInstance)リファレンス
findDOMNode(componentInstance)
findDOMNode を呼び出して、指定された React クラスコンポーネントインスタンスに対応するブラウザ DOM ノードを見つけます。
import { findDOMNode } from 'react-dom';
const domNode = findDOMNode(componentInstance);引数
componentInstance:Componentサブクラスのインスタンス。例えばクラスコンポーネント内からの場合はthisになります。
返り値
findDOMNode は、指定された componentInstance 内で最も上位にあるブラウザ DOM ノードを返します。コンポーネントが null をレンダーする場合や false をレンダーする場合、findDOMNode は null を返します。コンポーネントが文字列をレンダーする場合は findDOMNode はその値を含んでいるテキスト DOM ノードを返します。
注意点
-
コンポーネントは、配列や、複数の子要素を持つフラグメントを返す場合もあります。その場合
findDOMNodeは、最初の空ではない子に対応する DOM ノードを返します。 -
findDOMNodeはマウントされたコンポーネント(つまり、DOM に配置されたコンポーネント)でのみ動作します。まだマウントされていないコンポーネント内から呼び出そうとすると(例えば、まだ作成されていないコンポーネントのrender()内からfindDOMNode()を呼び出す場合)、例外がスローされます。 -
findDOMNodeは、呼び出したときの結果のみを返します。子コンポーネントが後で異なるノードをレンダーする場合、この変更は通知されません。 -
findDOMNodeはクラスコンポーネントインスタンスを受け取るため、関数コンポーネントで使用することはできません。
使用法
クラスコンポーネントのルート DOM ノードを見つける
クラスコンポーネントインスタンス(通常は、this)を引数にして findDOMNode を呼び出し、レンダーされた DOM ノードを見つけます。
class AutoselectingInput extends Component {
componentDidMount() {
const input = findDOMNode(this);
input.select()
}
render() {
return <input defaultValue="Hello" />
}
}この例では、input 変数は <input> DOM 要素にセットされます。これにより、それを使用して何かを行うことができます。例えば、以下の “Show example” をクリックすると入力欄がマウントされ、input.select() が入力欄のすべてのテキストを選択します。
import { Component } from 'react'; import { findDOMNode } from 'react-dom'; class AutoselectingInput extends Component { componentDidMount() { const input = findDOMNode(this); input.select() } render() { return <input defaultValue="Hello" /> } } export default AutoselectingInput;
代替手段
ref でコンポーネント自身の DOM ノードを読み取る
findDOMNode を使用しているコードは容易に壊れてしまいます。なぜなら JSX ノードと対応する DOM ノードを操作するコード間の接続が明示的でないためです。例えば、以下の <input /> を <div> でラップしてみてください。
import { Component } from 'react'; import { findDOMNode } from 'react-dom'; class AutoselectingInput extends Component { componentDidMount() { const input = findDOMNode(this); input.select() } render() { return <input defaultValue="Hello" /> } } export default AutoselectingInput;
コードは壊れてしまいます。なぜなら、<input> DOM ノードを期待していたのに、findDOMNode(this) が <div> DOM ノードの方を見つけてくるようになったためです。このような問題を避けるには、特定の DOM ノードを管理するために createRef を使用してください。
以下の例では、findDOMNode はもう使用されていません。代わりに、inputRef = createRef(null) がクラスのインスタンスフィールドとして定義されています。DOM ノードを読み取るには、this.inputRef.current を使用できます。それを JSX にアタッチするには、<input ref={this.inputRef} /> のようにレンダーします。これにより、DOM ノードを使用するコードがその JSX に接続されます。
import { createRef, Component } from 'react'; class AutoselectingInput extends Component { inputRef = createRef(null); componentDidMount() { const input = this.inputRef.current; input.select() } render() { return ( <input ref={this.inputRef} defaultValue="Hello" /> ); } } export default AutoselectingInput;
クラスコンポーネントがないモダンな React では、同等のコードにおいて代わりに useRef を呼び出します。
import { useRef, useEffect } from 'react'; export default function AutoselectingInput() { const inputRef = useRef(null); useEffect(() => { const input = inputRef.current; input.select(); }, []); return <input ref={inputRef} defaultValue="Hello" /> }
ref を使用して DOM を操作する方法についての詳細はこちら
転送された ref から子コンポーネントの DOM ノードを読み取る
以下の例では、findDOMNode(this) は別のコンポーネントに属する DOM ノードを見つけます。AutoselectingInput は MyInput をレンダーし、このカスタムコンポーネントはブラウザの <input> をレンダーします。
import { Component } from 'react'; import { findDOMNode } from 'react-dom'; import MyInput from './MyInput.js'; class AutoselectingInput extends Component { componentDidMount() { const input = findDOMNode(this); input.select() } render() { return <MyInput />; } } export default AutoselectingInput;
AutoselectingInput 内で findDOMNode(this) を呼び出すことで、DOM 要素である <input> が取得されたことに注意してください。対応する JSX が MyInput コンポーネントの中に隠蔽されているにも関わらず、こうなります。この例では便利に思えますが、壊れやすいコードになってしまいます。後で MyInput を編集して、<input> の周りに <div> を追加するとどうなるでしょうか。(<input> が見つかることを期待している)AutoselectingInput のコードが壊れてしまいます。
この例の findDOMNode を置き換えるには、2 つのコンポーネントが連携する必要があります:
AutoSelectingInputは前述の例のようにrefを宣言して<MyInput>に渡す必要があります。MyInputをforwardRef付きで宣言するようにし、refを受け取って<input>ノードに転送する必要があります。
上記を行ったバージョンを以下に示します。もはや findDOMNode は必要ありません。
import { createRef, Component } from 'react'; import MyInput from './MyInput.js'; class AutoselectingInput extends Component { inputRef = createRef(null); componentDidMount() { const input = this.inputRef.current; input.select() } render() { return ( <MyInput ref={this.inputRef} /> ); } } export default AutoselectingInput;
クラスの代わりに関数コンポーネントを使用する場合、コードは以下のようになります。
import { useRef, useEffect } from 'react'; import MyInput from './MyInput.js'; export default function AutoselectingInput() { const inputRef = useRef(null); useEffect(() => { const input = inputRef.current; input.select(); }, []); return <MyInput ref={inputRef} defaultValue="Hello" /> }
<div> 要素のラッパを追加する
コンポーネントによっては子要素の位置やサイズを知る必要があります。この場合、findDOMNode(this) で子要素を見つけ、getBoundingClientRect のような DOM メソッドを使って計測を行いたくなるかもしれません。
現在、このユースケースに直接対応できるものは存在しません。これが findDOMNode が非推奨となっているにも関わらずまだ完全に React から削除されていない理由です。当面は、コンテンツの周りにラッパとして <div> ノードをレンダーし、そのノードへの ref を取得するという回避策をお試しください。ただし、余分なラッパはスタイリングを壊す可能性があります。
<div ref={someRef}>
{children}
</div>任意の子要素にフォーカスやスクロールを行いたい場合も同様です。