LESSON 09 · 約25分
refで、DOMへ必要な操作をする
再描画に使うstateと、DOM参照などを保つrefの役割を分けます。
コードを試す前に
01のVite reactテンプレート(JavaScript/JSX)を使います。特記のないApp.jsxは、そのレッスンだけで動く独立した例です。例同士を連結しないでください。
短い学習用の例です。各App.jsxは独立した例で、順に追記して一つの完成品にする形式ではありません。ファイル名、依存関係、未定義部分の前提は注記に記載します。問題内の抜粋や空欄は、そのまま実行するための完成コードではありません。
開発環境の準備を確認する →このレッスンでわかること
- ref経由で入力へフォーカスできる
- refの更新だけでは再描画されないと説明できる
refは表示以外の値を覚える
useRefはcurrentというプロパティを持つオブジェクトを返し、再描画をまたいで保持します。currentを変更しても、それ自体では再描画が起きません。画面に表示するカウントや入力内容はstate、タイマーIDやDOMへの参照はrefという使い分けから始めます。
DOM操作は必要な範囲だけ
inputへrefを渡すと、DOMが配置された後でcurrentから入力要素を参照できます。ボタンのイベントでfocus()を呼べば、入力へ移動できます。Reactが管理する子要素をremoveしたりinnerHTMLで作り直したりすると、Reactの状態とDOMが食い違います。
フォーカスも利用者の流れに合わせる
ページを開くたびに突然フォーカスを奪うより、利用者が「入力へ移動」を選んだときに動かすほうが意図を伝えやすい場合があります。DOMがまだない・すでに消えた状態にも備え、current?.focus()のようにnullを扱います。
ボタンから入力へ移動する
import { useRef, useState } from 'react';
export default function App() {
const inputRef = useRef(null);
const [title, setTitle] = useState('');
return (
<main>
<h1>次のテーマ</h1>
<button type="button" onClick={() => inputRef.current?.focus()}>
テーマ入力へ移動
</button>
<label>テーマ
<input ref={inputRef} value={title}
onChange={event => setTitle(event.target.value)} />
</label>
<p>入力中: {title || '未入力'}</p>
</main>
);
}inputRefはDOM操作、titleは画面表示を担当します。refを読むのはクリック時です。
TRY IT YOURSELF
入力へフォーカスを移す
- 移動ボタンをマウスとキーボードの両方で押し、入力へフォーカスが移ることを確認する
- 「消して入力へ戻る」ボタンを追加し、setTitleとfocusをイベントで実行する
- 表示を変える値をrefへ置き換えると何が不足するか説明する
できたらOK:入力値はstateで描画され、ボタン操作時だけrefでフォーカスを移せる
QUICK CHECK
理解を確かめよう
公式資料でもう少し詳しく
ここまで読めたら、ひとつ前進。