こう 聞かれます
- 「useRef は
何に 使いますか」 - 「useState と useRef の違いは」
- 「入力欄に
フォーカスを 当てるには、 どうしますか」
面接官が 見ている点
- ref は current を
変えても 描き直さない、と言えるか - 画面に
出す値は state、 画面に 出さず 覚えておくだけの 値は ref、と 分けられるか - DOM の
要素に 直接触る 場面 (フォーカス、 スクロール、 大きさを 測る ) を 挙げられるか - 描画の
中で ref を 読み 書きしない、という 決まりを 知っているか
短い答え
- useRef は、
描き直しを またいで 値を 覚えておく 箱を 作ります。 current を 書き換えても、 描き直しは 起きません。 - 画面に
出す値は useState、 画面に 出さず 覚えておくだけの 値は useRef に 入れます。 setInterval の 番号や、 前の 値の 控えなどが ref に 向きます。 - もう 1 つの
使い方は DOM の 要素を 指す ことで、 ref を JSX の ref に 渡すと、 要素に フォーカスを 当てる、 スクロールさせる、 大きさを 測るといった 操作が できます。
この
少し 詳しい答え
state と ref の違い
| useState | useRef | |
|---|---|---|
| 変えると | 描き直す | 描き直さない |
| 変え方 | set 関数を呼ぶ | current に代入する |
| 新しい | 次の描画 | 代入したすぐ後 |
| 向いている値 | 画面に出す値 | 画面に |
画面に 出さない値を持つ
TypeScript (JSX)
function Stopwatch() {
const [seconds, setSeconds] = useState(0);
const timerId = useRef<number | null>(null); // 画面に出さないので ref
function start() {
if (timerId.current !== null) window.clearInterval(timerId.current); // 二重に動かさない
timerId.current = window.setInterval(() => setSeconds((s) => s + 1), 1000);
}
function stop() {
if (timerId.current !== null) window.clearInterval(timerId.current);
timerId.current = null;
}
return (
<>
<p>{seconds} 秒</p>
<button onClick={start}>開始</button>
<button onClick={stop}>停止</button>
</>
);
}timerId を
DOM の 要素に触る
TypeScript (JSX)
function SearchBox() {
const inputRef = useRef<HTMLInputElement>(null);
return (
<>
<input ref={inputRef} />
<button onClick={() => inputRef.current?.focus()}>検索欄へ</button>
</>
);
}React 19 からは、
描画の 中で 読み 書きしない
ref は
よく ある間違い
- 画面に
出す値を ref に入れる 変えても 描き直されず、 画面が 古いままです。 state にします - 描画の
中で ref.current を 書き換える 描画は 何度呼ばれても 同じ 結果を 返す決まりです。 イベントの 処理か useEffect で 書き換えます - 何でも ref で DOM を
直接書き換える React の 描く 結果と ずれます。 文字や 表示の 切り 替えは state で 書き、 ref は フォーカスや 測定のような React が 持たない 操作に使います
深掘りの問い
- 「前回の
描画の 値と 比べたいときは」前の 値を state に 持ち、 描画の 中で 今の 値と 違えば、 その state を 更新して 比べる、と 答えます。 描画の 中で ref.current を 読み 書きする 書き方は 使いません - 「最初に
表示された ときに、 入力欄へ フォーカスするには」 autoFocus を 使うか、 useEffect の 中で ref の focus を 呼ぶ、 と答えます - 「setTimeout の
中で 最新の state を 読みたいときは」更新関数を 使うか、 最新の 値を ref にも 入れておいて 読む、と答えます
