0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【React 19.2】useRefでDOMを直接操作する基本手順と注意点

Posted at

はじめに

Reactは通常、ステート(state)とプロップス(props)を使って画面を更新する「宣言的」なUIライブラリです。しかし開発をしていると、特定の入力フォームにフォーカスを当てたり、特定の位置までスクロールさせたりといった、ブラウザのDOM要素を直接操作したい場面に遭遇します。

この記事では、ReactにおいてDOMを操作するための標準的なフックである useRef の使い方を解説します。

なお、本記事は React 19.2 を前提として記述しています。React 19系では ref の扱いが従来よりも簡潔になっているため、その点についても触れていきます。

useRefとは何か

useRef は、再レンダリングを発生させずに情報を保持しておくためのフックです。コンポーネントが再描画されてもリセットされない「値を書き換えられる箱」のようなものだとイメージしてください。

DOM操作においては、この「箱」の中にHTML要素(DOMノード)への参照を格納するために使用します。

基本的なDOM操作の実装手順

DOMを操作するためには、以下の3つのステップを踏みます。

  1. useRef フックをインポートし、初期値 null で宣言する。
  2. 操作したいJSXタグの ref 属性に、作成した変数を渡す。
  3. イベントハンドラ内などで ref.current を通じてDOMメソッドを呼び出す。

処理の流れ(Mermaid図解)

Reactがコンポーネントを画面に描画し、ref にDOMノードが格納されるまでの流れを整理します。

実践例:テキストボックスへのフォーカス制御

ボタンをクリックすると、入力欄(input要素)に自動的にカーソルが当たり、入力可能な状態になる機能を実装してみましょう。

import { useRef } from 'react';

export default function Form() {
  // 1. refオブジェクトを作成(初期値はnull)
  const inputRef = useRef(null);

  function handleClick() {
    // 3. ref.currentでDOMノードにアクセスし、focus()メソッドを実行
    // inputRef.currentは実際の <input> DOM要素を指しています
    if (inputRef.current) {
      inputRef.current.focus();
    }
  }

  return (
    <>
      {/* 2. 操作したい要素のref属性に渡す */}
      <input ref={inputRef} type="text" placeholder="ここに入力" />
      
      <button onClick={handleClick}>
        入力欄にフォーカスする
      </button>
    </>
  );
}

このコードでは、ブラウザが画面に <input> を表示した直後に、Reactが inputRef.current にそのDOMノードを代入します。ユーザーがボタンを押す頃には current に中身が入っているため、 focus() メソッドを呼び出すことができます。

React 19での変更点:子コンポーネントへのref渡し

これまで(React 18以前)は、自作のコンポーネントに対して ref を渡したい場合、 forwardRef という特別な関数でコンポーネントをラップする必要がありました。

React 19からはこの制限が撤廃され、 ref を通常のプロップス(props)と同じように扱うことができます。

React 19.2 での書き方

import { useRef } from 'react';

// 子コンポーネント:refをpropsとして受け取るだけ
function MyInput({ placeholder, ref }) {
  return <input ref={ref} placeholder={placeholder} />;
}

// 親コンポーネント
export default function Parent() {
  const inputRef = useRef(null);

  return (
    <>
      {/* forwardRefなしで直接refを渡せる */}
      <MyInput ref={inputRef} placeholder="React 19スタイル" />
      
      <button onClick={() => inputRef.current.focus()}>
        フォーカス
      </button>
    </>
  );
}

これにより、コードがより直感的でシンプルになりました。

DOM操作時の重要な注意点

DOM操作は強力ですが、Reactの管理外で画面を書き換える行為です。以下の点に注意してください。

1. レンダリング中にrefを読み書きしない

ref.current の変更は再レンダリングをトリガーしません。そのため、コンポーネントの表示内容(JSX)を決める計算の途中で ref.current を読み書きしてはいけません。予期せぬ挙動の原因になります。

DOM操作は必ず、レンダリングが終わった後である「イベントハンドラ」や「useEffect」の中で行います。

2. nullチェックを行う

ref.current の初期値は null です。また、条件付きレンダリングなどで要素が画面に存在しない場合も null になる可能性があります。

TypeScriptを使用している場合や、要素の存在が不確定な場合は、必ず inputRef.current?.focus() のようにオプショナルチェーンを使うか、if文で存在確認を行いましょう。

まとめ

  • DOM操作には useRef を使用し、 ref.current を通じてアクセスする。
  • React 19.2では forwardRef が不要になり、コンポーネント間での ref の受け渡しが簡単になった。
  • DOM操作はあくまで「逃げ道」であり、基本はReactのステート管理で解決できないか検討する。
  • レンダリング中にはアクセスせず、イベントハンドラやuseEffect内で操作する。

useRef を適切に使いこなすことで、Reactの宣言的な良さを保ちつつ、必要な場面で柔軟なUI操作を実現できます。ぜひ活用してみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?