ダメなパターン
ReactでDOMを操作したいときに、document.getElementById
やdocument.querySelector
などを使うことは推奨されていません
export const Form = ()=> {
const inputElement = document.getElementById('myInput')
const handleClick = () => inputElement.focus()
return (
<>
<input id="myInput" />
<button onClick={handleClick}>Focus the input</button>
</>
)
}
なぜダメか
仮想DOMによる差分更新が破綻してしまい、宣言的UIの思想に反するからです。
〜 完 〜
そもそも…
宣言的UIってなんだっけ?
宣言的UIは、初めに目的のUIの形を宣言し、それに基づいて処理が実行されるというアプローチです。
命令的UIと比較するとわかりやすいです。
TODOアプリを例にして考えてみます
TODOを追加したらリストにチェックボックスと文言、削除ボタンが生成されます。
命令的UI(例:jQuery)では、生成されるDOMを順番に命令していきます。
命令的な書き方は順序通りに書くことができますが、最終的にどのようなDOMが生成されるかを想像することが難しいです。
一方、Reactなどの宣言的UIでは、最終的なDOMの形を先に宣言し、値や情報を渡すことでUIを構築します。
これにより、最終的なUIがどのようなものになるかをより明確に理解することができます。
宣言的UIの思想では、DOMを直接操作したり生成したりせずに、UIの形を宣言することが大切です!
仮想DOMってなんだっけ?
仮想DOMは、実際のDOMをレンダリングする前に、仮想のDOMの構造を計算することで、高速な表示を実現する手法です。
そして、この仮想DOMの生成はReactの視点から行われます。
Reactの外部で直接DOMを操作すると、仮想DOMの生成の対象外になり、変更が正しく検知されなくなってしまいます。
つまり?
- 直接的なDOM操作を使用すると、Reactの仕組みをバイパスしてしまい、コンポーネントの状態とDOMが同期しなくなる可能性があること
- 宣言的にUIを構成することで、Reactのメリットである最終的なUIのイメージが明確になること
上記のような点から、Reactで直接DOM操作を行うことは推奨されません。
どうすればいいか
ReactでDOMにアクセスする時はuseRef
を使います。
Reactが提供する手段によってDOM操作を行うことで、上記の懸念を解消できます。
export const Form = ()=> {
const inputRef = useRef(null)
const handleClick = () => inputRef.current?.focus()
return (
<>
<input ref={inputRef} />
<button onClick={handleClick}>Focus the input</button>
</>
)
}
ただし、公式ドキュメントでも説明されているように、refは最終手段として使用するべきです。
可能な限りDOMを操作せずに問題を解決する方法を考えるようにしましょう。