findDOMNode
findDOMNode
は、React class component インスタンスのブラウザ DOM ノードを見つけます。
const domNode = findDOMNode(componentInstance)
リファレンス
findDOMNode(componentInstance)
findDOMNode
を呼び出して、指定された React class component インスタンスのブラウザ DOM ノードを見つけます。
import { findDOMNode } from 'react-dom';
const domNode = findDOMNode(componentInstance);
引数
componentInstance
: Component サブクラスのインスタンス。例えば、クラスコンポーネントにある this になります。
返り値
findDOMNode
は、指定された componentInstance
に最も近いブラウザ DOM ノードを返します。コンポーネントが null
をレンダーする場合や false
をレンダーする場合、findDOMNode
は null
を返します。コンポーネントが文字列をレンダーする場合は findDOMNode
は値を含むテキスト DOM ノードを返します。
注意点
-
コンポーネントは、配列や複数の子要素を持つ Fragment を返す場合もあります。その場合、
findDOMNode
は、最初の空ではない子に対応する DOM ノードを返します。 -
findDOMNode
はマウントされたコンポーネント(つまり、DOM に配置されたコンポーネント)でのみ動作します。まだマウントされていないコンポーネント内から呼び出そうとすると(例えば、まだ作成されていないコンポーネントのrender()
内からfindDOMNode()
を呼び出す場合)、例外がスローされます。 -
findDOMNode
は、呼び出したときの結果のみを返します。子コンポーネントが後で異なるノードをレンダーする場合、この変更を通知されません。 -
findDOMNode
はクラスコンポーネントインスタンスを受け取るため、関数コンポーネントで使用することはできません。
使用法
クラスコンポーネントのルート DOM ノードを見つける
class component インスタンス(通常は、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 はマウントされ、input.select()
は input にあるすべてのテキストを選択します。
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" /> }
refs を使用して DOM を操作する方法についての詳細はこちら
forwarded ref から子コンポーネントの DOM ノードを読み取る
この例では、findDOMNode(this)
は別のコンポーネントに属する DOM ノードを見つけます。AutoselectingInput
は、ブラウザの <input>
をレンダーする独自のコンポーネントである MyInput
をレンダーします。
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>
を取得します。しかし、この <input>
の JSX は MyInput
コンポーネントの中に隠れています。この上の例では便利に思えますが、壊れやすいコードになりやすいです。MyInput
を編集して、それをラップする <div>
を追加するとどうなるでしょうか。AutoselectingInput
のコードが壊れます(<input>
が見つかることを期待している)。
この例の findDOMNode
を置き換えるには、2 つのコンポーネントが連携する必要があります:
- 1.
AutoSelectingInput
はref
を宣言し、前述の例のように<MyInput>
に渡す必要があります。 - 2.
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>
これは、任意の子要素にフォーカスや、スクロールにも適用されます。