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>
任意の子要素にフォーカスやスクロールを行いたい場合も同様です。