useRefとは、再レンダリングをまたいで値を持ち続けられ、書き換えても再レンダリングが起きない「入れ物」を作るReactのフックです。 const ref = useRef(初期値) で作り、ref.current で読み書きします。主な用途は、input などのDOM要素を参照してフォーカスやスクロールを行うことと、タイマーIDのように画面に出さない値を持っておくことの2つです。

この記事は、冒頭の早見表と判断フローで「useStateとどちらを使うか」をすぐ決められる構成にしています。そのうえで、currentがnullになる・画面が更新されない・レンダリング中に読み書きする、という3つのつまずきを再現し、TypeScriptの型の書き方と、forwardRefが不要になったReact 19の書き方までを扱います。コードと出力は React 19.3.0 で動かして確かめたものです。

useRefとuseStateの違いの早見表

比べる点 useState useRef
作り方 const [value, setValue] = useState(0) const ref = useRef(0)
読み方 value ref.current
書き方 setValue(1) ref.current = 1
書き換えたときの再レンダリング 起きる 起きない
値が反映されるタイミング 次のレンダリングから 代入した直後から
再レンダリングをまたいだ保持 される される
レンダリング中の読み取り できる(そのための値) 避ける(イベントやエフェクトの中で読む)
向いている値 画面に表示する値、表示の切り替えに使う値 DOM要素、タイマーID、画面に出さない記録用の値

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「React useRefの使い方|DOM参照とuseStateとの違い」

どちらを使うかの判断フロー

迷ったときは、「その値が変わったら画面も変わってほしいか」を最初に考えます。

flowchart TD
  A[値を持っておきたい] --> B{値が変わったら画面も変えたい}
  B -- はい --> C[useState]
  B -- いいえ --> D{DOM要素を直接操作したい}
  D -- はい --> E[useRef を要素の ref に渡す]
  D -- いいえ --> F{再レンダリングをまたいで覚えておきたい}
  F -- はい --> G[useRef に値を入れる]
  F -- いいえ --> H[ふつうの変数や計算で足りる]

具体的な値での判断例です。

持ちたい値 選ぶもの 理由
入力欄の文字、チェックの有無 useState 画面に表示する
モーダルの開閉、選択中のタブ useState 表示の切り替えに使う
input 要素そのもの(フォーカス用) useRef DOM要素への参照
setInterval / setTimeout のID useRef 止めるときに使うだけで表示しない
送信済みかどうかの記録(二重送信の防止) useRef 判定に使うだけで表示しない
一覧の件数、合計金額 どちらも使わない 元のデータから計算できる

この記事の確認環境

項目 バージョン
React / react-dom 19.3.0(開発ビルド)
@types/react 19.3.0
TypeScript 7.0.2(tsc --noEmit、strict)
ESLint / eslint-plugin-react-hooks 9.39.5 / 7.1.1
実行 Node.js 22.22.2、jsdom 30.1.1、JSXの変換は esbuild 0.28.2

動きは jsdom 上で createRoot を使って描画し、クリックをスクリプトから発生させて確かめました。実際のブラウザでの操作確認と、React 18 以前での動作確認は未実行です。型エラーの文面は tsc の出力から、ファイル名と行番号を省いて載せています。

基本の使い方1:DOM要素を参照してフォーカスする

DOM要素を参照する手順は3つです。useRefで入れ物を作る → 要素の ref 属性に渡す → イベントの中で current を使う。

import { useRef } from "react";

export function SearchBox() {
  // 1. 入れ物を作る(最初は null)
  const inputRef = useRef<HTMLInputElement>(null);

  return (
    <>
      {/* 2. 要素の ref に渡す */}
      <input ref={inputRef} placeholder="検索" />
      {/* 3. イベントの中で current を使う */}
      <button onClick={() => inputRef.current?.focus()}>フォーカス</button>
    </>
  );
}

ボタンを押す前後で、フォーカスのある要素(document.activeElement)を調べた結果です。

クリック前: BODY
クリック後: INPUT(placeholder: 検索)

Reactは要素を画面に反映したあとで inputRef.current にその要素を入れ、要素が画面から外れると null に戻します。?. を付けているのは、current が null の可能性があるためです。

DOM参照でよく使う操作をまとめます。

やりたいこと 書き方
フォーカスを当てる inputRef.current?.focus()
入力内容を全選択する inputRef.current?.select()
要素までスクロールする ref.current?.scrollIntoView({ behavior: "smooth" })
大きさや位置を測る ref.current?.getBoundingClientRect()
動画を再生・停止する videoRef.current?.play() / pause()

表示内容の変更(文字を変える、クラスを付け替える、要素を足す・消す)は、ref で直接触らず、stateとJSXで表現します。refで行うのは、フォーカス・スクロール・計測・再生のように、JSXでは表しにくい操作と考えると線引きしやすくなります。

基本の使い方2:画面に出さない値を持っておく

タイマーIDを保持する

setInterval のIDは、止めるときに必要ですが画面には出しません。useRefに入れておく典型的な値です。

import { useEffect, useRef, useState } from "react";

export function Stopwatch() {
  const [count, setCount] = useState(0);
  const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);

  const start = () => {
    if (timerRef.current !== null) return; // 二重に開始しない
    timerRef.current = setInterval(() => setCount((c) => c + 1), 100);
  };

  const stop = () => {
    if (timerRef.current !== null) {
      clearInterval(timerRef.current);
      timerRef.current = null;
    }
  };

  // 画面から外れるときにも止める
  useEffect(() => stop, []);

  return (
    <>
      <output>{count}</output>
      <button onClick={start}>開始</button>
      <button onClick={stop}>停止</button>
    </>
  );
}

「開始」を2回続けて押し、350ミリ秒後に「停止」を押した結果です。

350ms後に停止した時点: 3
さらに250ms待ったあと: 3

開始を2回押してもタイマーは1つだけで、停止後はカウントが進んでいません。表示する count は useState、止めるためのIDは useRef という分担になっています。

非同期処理の中から最新の値を読む

イベントハンドラーの中で読むstateは、そのレンダリング時点の値です。時間がたってから実行される処理で「いまの最新の値」を読みたいときは、refに写しておきます。

function Stale() {
  const [text, setText] = useState("a");
  const latest = useRef(text);

  // レンダリングが終わるたびに最新の値を写す
  useEffect(() => {
    latest.current = text;
  }, [text]);

  const later = () =>
    setTimeout(() => {
      console.log("state(クリック時点):", text, "/ ref(最新):", latest.current);
    }, 50);

  return (
    <>
      <button onClick={later}>50ms後に表示</button>
      <button onClick={() => setText("b")}>変更</button>
    </>
  );
}

「50ms後に表示」を押してすぐ「変更」を押した結果です。

state(クリック時点): a / ref(最新): b

stateはクリックした時点の a のまま、refは変更後の b を返しています。

つまずき1:currentがnullになる

ref.current が null になる場面は、主に3つあります。

場面 理由 直し方
レンダリング中に読んだ 要素がまだ画面に反映されていない useEffect やイベントハンドラーの中で読む
条件付きで表示する要素だった 表示されていない間は要素が存在しない ?. や if で null を確かめてから使う
自作コンポーネントに ref を渡した 子が ref を要素に渡していない 子で ref を受け取り、内側の要素に渡す

レンダリング中はまだnull

function Timing() {
  const boxRef = useRef<HTMLDivElement>(null);

  console.log("render中:", boxRef.current === null ? "null" : boxRef.current.tagName);

  useEffect(() => {
    console.log("useEffect内:", boxRef.current?.tagName);
  }, []);

  return <div ref={boxRef}>box</div>;
}
render中: null
useEffect内: DIV

コンポーネントの関数が動いている時点では、まだDOMが作られていません。要素が入るのは画面への反映が終わったあとなので、表示直後に何かしたいときは useEffect の中に書きます。

// 表示されたらすぐフォーカスを当てる
useEffect(() => {
  inputRef.current?.focus();
}, []);

条件付きで表示する要素

function Cond() {
  const [open, setOpen] = useState(false);
  const panelRef = useRef<HTMLDivElement>(null);

  const check = () =>
    console.log(
      "open=" + open + " current:",
      panelRef.current === null ? "null" : panelRef.current.tagName
    );

  return (
    <>
      <button onClick={() => setOpen((o) => !o)}>切替</button>
      <button onClick={check}>確認</button>
      {open && <div ref={panelRef}>panel</div>}
    </>
  );
}

確認 → 切替 → 確認 → 切替 → 確認 の順に押した結果です。

open=false current: null
open=true current: DIV
open=false current: null

要素が表示されている間だけ current に入り、非表示に戻ると null に戻ります。条件付きの要素を参照するときは、null のときは何もしない書き方(?. や早期 return)にしておくと安心です。

自作コンポーネントに渡したrefが届かない

// 子:ref を受け取っていない
function PlainInput(props: { placeholder?: string }) {
  return <input placeholder={props.placeholder} />;
}

function Parent() {
  const r = useRef<HTMLInputElement>(null);
  useEffect(() => {
    console.log("current:", r.current);
  }, []);
  // 型チェックを外して ref を渡した場合
  return <PlainInput {...({ ref: r } as any)} placeholder="x" />;
}
current: null

React 19.3.0 では、警告は出ずに null のままでした。React 19 で ref は通常のpropsになったため、子が受け取って内側の要素へ渡さない限り、どこにもつながりません。 直し方は後半の「React 19の書き方」で扱います。なお TypeScript を使っていれば、Propsに ref がないコンポーネントへ ref を渡した時点で型エラーになり、実行前に気付けます。

error TS2322: Type '{ ref: RefObject<HTMLInputElement | null>; placeholder: string; }' is not assignable to type 'IntrinsicAttributes & { placeholder?: string | undefined; }'.
  Property 'ref' does not exist on type 'IntrinsicAttributes & { placeholder?: string | undefined; }'.

つまずき2:refを書き換えても画面が更新されない

refの値をJSXに表示して、ボタンで増やす例です。

function RefCounter() {
  const countRef = useRef(0);
  const [count, setCount] = useState(0);

  return (
    <>
      <button onClick={() => { countRef.current += 1; }}>ref +1</button>
      <button onClick={() => setCount((c) => c + 1)}>state +1</button>
      <p>ref: {countRef.current} / state: {count}</p>
    </>
  );
}
初期:            ref: 0 / state: 0
refを3回押した:  ref: 0 / state: 0
stateを1回押した: ref: 3 / state: 1

refを3回増やしても表示は 0 のままです。値そのものは 3 に変わっていますが、refの書き換えは再レンダリングを起こさないので、画面には出てきません。 そのあと state を更新して再レンダリングが起きたとき、はじめて 3 が表示されました。

この「別のきっかけで再レンダリングされたときだけ表示が追い付く」動きは、原因が分かりにくいつまずきになりがちです。画面に出す値は useState で持つ、と決めておくのが確実です。

つまずき3:レンダリング中にrefを読み書きする

レンダリングの回数を数えようとして、コンポーネントの本体で ref を増やす例です。

function RenderCount({ label }: { label: string }) {
  const renders = useRef(0);
  renders.current += 1; // レンダリング中に書き込み

  const [, setN] = useState(0);
  return (
    <>
      <button onClick={() => setN((n) => n + 1)}>更新</button>
      <p>{label} 描画回数: {renders.current}</p>
    </>
  );
}

通常の描画と、StrictMode で包んだ描画を比べました。

通常       初回: 描画回数: 1  → 更新1回後: 描画回数: 2
StrictMode 初回: 描画回数: 2  → 更新1回後: 描画回数: 4

StrictMode では、開発時にコンポーネントの関数が2回ずつ呼ばれます。レンダリング中に ref を書き換えていると、呼ばれた回数だけ値が進み、環境によって結果が変わります。 Reactは「同じ入力なら同じ結果を返す」ことを前提に、レンダリングを途中でやり直したり2回実行したりするため、レンダリング中の読み書きは結果が予測しにくくなります。

ESLintが検出してくれる

eslint-plugin-react-hooks 7.1.1 の推奨設定で、上のコード(JSX版)を検査した結果の抜粋です。

5:3   error  Error: Cannot access refs during render

React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the `current` property) during render can cause your component not to update as expected (https://react.dev/reference/react/useRef).

> 5 |   renders.current += 1;
    |   ^^^^^^^^^^^^^^^ Cannot update ref during render
  react-hooks/refs

7:60  error  Error: Cannot access refs during render
> 7 |   return <button onClick={() => setN((n) => n + 1)}>描画回数: {renders.current}</button>;
    |                                                            ^^^^^^^^^^^^^^^ Cannot access ref value during render
  react-hooks/refs

書き込み(5行目)と、JSXでの読み取り(7行目)の両方が react-hooks/refs ルールで指摘されました。

直し方:イベントかエフェクトの中へ移す

function RenderCountOk() {
  const commits = useRef(0);
  const [n, setN] = useState(0);

  // 画面への反映が終わるたびに数える
  useEffect(() => {
    commits.current += 1;
  });

  return (
    <>
      <button onClick={() => setN((v) => v + 1)}>更新</button>
      <button onClick={() => console.log("commits:", commits.current, "n:", n)}>
        確認
      </button>
    </>
  );
}

読み書きの場所ごとの可否を整理します。

場所 refの読み書き
イベントハンドラー(onClick など) できる
useEffect / useLayoutEffect の中 できる
ref コールバックの中 できる
コンポーネント本体(return より前) 避ける
JSXの中({ref.current}) 避ける。表示したい値は state にする

React公式のuseRefのリファレンスには、例外として初回だけ値を作る初期化が挙げられています(今回ページを開いて確認しました)。結果が毎回同じになるため、レンダリング中に書いても問題ないとされています。

function Video() {
  const playerRef = useRef<VideoPlayer | null>(null);
  if (playerRef.current === null) {
    playerRef.current = new VideoPlayer(); // 最初の1回だけ作る
  }
  // ...
}

useRef(new VideoPlayer()) と書くと、使われないインスタンスがレンダリングのたびに作られます。作るのに手間のかかるオブジェクトは、上の形で1回だけ作ります(VideoPlayer は公式の例にある仮のクラスで、この部分は未実行です)。

TypeScriptでの型の書き方

用途別の書き方

用途 書き方 current の型
DOM要素を参照する useRef<HTMLInputElement>(null) HTMLInputElement | null
数値などを持つ useRef(0) number(初期値から推論)
あとで入れる値 useRef<number | null>(null) number | null
タイマーID useRef<ReturnType<typeof setInterval> | null>(null) 環境に合ったIDの型、または null
初期値なし useRef<string>(undefined) string | undefined

DOM要素の型は、タグごとに決まっています。

要素 型
input HTMLInputElement
textarea HTMLTextAreaElement
button HTMLButtonElement
div HTMLDivElement
form HTMLFormElement
video HTMLVideoElement
canvas HTMLCanvasElement
どの要素でもよい HTMLElement

よく出る型エラーと直し方

引数なしの useRef(TS2554)

const a = useRef<HTMLInputElement>();
error TS2554: Expected 1 arguments, but got 0.

React 19 の型定義では useRef の引数が必須になりました(React 19 アップグレードガイドに記載。今回ページを開いて確認しました)。DOM参照なら useRef<HTMLInputElement>(null)、値なら useRef<string>(undefined) のように初期値を渡します。

current が null かもしれない(TS18047)

const b = useRef<HTMLInputElement>(null);
b.current.focus();
error TS18047: 'b.current' is possibly 'null'.

直し方は場面で選びます。

書き方 向いている場面
b.current?.focus() null なら何もしなくてよいとき。まずこれ
if (!b.current) return; そのあと何行も使うとき
b.current!.focus() 必ず存在すると言い切れるときだけ

要素の型が合っていない(TS2322)

const c = useRef<HTMLDivElement>(null);
return <input ref={c} />;
error TS2322: Type 'RefObject<HTMLDivElement | null>' is not assignable to type 'Ref<HTMLInputElement> | undefined'.
  Type 'RefObject<HTMLDivElement | null>' is not assignable to type 'RefObject<HTMLInputElement | null>'.
    Type 'HTMLDivElement | null' is not assignable to type 'HTMLInputElement | null'.
      Type 'HTMLDivElement' is missing the following properties from type 'HTMLInputElement': accept, alt, autocomplete, capture, and 54 more.

長い文面ですが、1行目に「div用の入れ物を input に渡している」ことが出ています。ジェネリクスを渡す先の要素に合わせます。

RefObject の型に null が入っていない(TS2322)

const b = useRef<HTMLInputElement>(null);
const t: RefObject<HTMLInputElement> = b;
error TS2322: Type 'RefObject<HTMLInputElement | null>' is not assignable to type 'RefObject<HTMLInputElement>'.
  Type 'HTMLInputElement | null' is not assignable to type 'HTMLInputElement'.
    Type 'null' is not assignable to type 'HTMLInputElement'.

useRef<HTMLInputElement>(null) の戻り値は RefObject<HTMLInputElement | null> です。refを引数やpropsで受け渡す関数では、受け取る側の型も RefObject<HTMLInputElement | null> と書きます。

ref コールバックで値を返している(TS2322)

<div ref={(el) => (n.current = el ? 1 : 0)} />
error TS2322: Type '(el: HTMLDivElement | null) => 0 | 1' is not assignable to type 'Ref<HTMLDivElement> | undefined'.
  Type '(el: HTMLDivElement | null) => 0 | 1' is not assignable to type '(instance: HTMLDivElement | null) => void | (() => VoidOrUndefinedOnly)'.
    Type 'number' is not assignable to type 'void | (() => VoidOrUndefinedOnly)'.

アロー関数の本体を丸かっこで書くと、代入した値がそのまま戻り値になります。React 19 では ref コールバックの戻り値が「後片付けの関数」として扱われるため、それ以外の値を返すと型エラーになります。波かっこで囲んで、値を返さない形にします。

<div ref={(el) => { n.current = el ? 1 : 0; }} />

React 19の書き方:forwardRefなしでrefを受け取る

自作コンポーネントの内側にある要素を、親から参照したい場合の書き方です。React 19 から、関数コンポーネントは ref を通常のpropsとして受け取れるようになりました(React 19 のリリース記事で確認)。

新旧の書き方を並べる

import { forwardRef, useRef, type Ref } from "react";

// これまでの書き方:forwardRef で包み、第2引数で ref を受け取る
const OldInput = forwardRef<HTMLInputElement, { label: string }>(
  function OldInput({ label }, ref) {
    return (
      <label>
        {label}
        <input ref={ref} name="old" />
      </label>
    );
  }
);

// React 19 の書き方:ref を props の1つとして受け取る
type NewInputProps = { label: string; ref?: Ref<HTMLInputElement> };

function NewInput({ label, ref }: NewInputProps) {
  return (
    <label>
      {label}
      <input ref={ref} name="new" />
    </label>
  );
}

// 親:どちらも同じ使い方
function Form() {
  const a = useRef<HTMLInputElement>(null);
  const b = useRef<HTMLInputElement>(null);
  return (
    <>
      <OldInput label="旧" ref={a} />
      <NewInput label="新" ref={b} />
      <button onClick={() => a.current?.focus()}>旧にフォーカス</button>
      <button onClick={() => b.current?.focus()}>新にフォーカス</button>
    </>
  );
}

それぞれのボタンを押したあと、フォーカスのある要素の name を調べた結果です。

forwardRef 版: old
ref props 版:  new

React 19.3.0 では、どちらの書き方も動きました。

比べる点 forwardRef ref をpropsで受け取る
使えるバージョン React 18 以前から使える React 19 以降
書き方 関数を forwardRef で包む。ref は第2引数 通常のpropsと同じ。分割代入で受け取る
型 forwardRef<要素の型, Propsの型> Propsに ref?: Ref<要素の型> を足す
これから React 19 のリリース記事に、将来のバージョンで非推奨にして取り除く方針と記載 新しく書くならこちら

React 18 以前も対象にするライブラリでは forwardRef を使い続け、React 19 以降だけを対象にするアプリでは ref props へ、という選び方になります。

公開する操作を絞る(useImperativeHandle)

親にDOM要素をまるごと渡すのではなく、「消去する」のような決まった操作だけを公開したいときは useImperativeHandle を使います。

import { useImperativeHandle, useRef, type Ref } from "react";

type ClearableHandle = { clear: () => void };

function ClearableInput({ ref }: { ref?: Ref<ClearableHandle> }) {
  const inner = useRef<HTMLInputElement>(null);

  useImperativeHandle(ref, () => ({
    clear() {
      if (inner.current) inner.current.value = "";
    },
  }), []);

  return <input ref={inner} defaultValue="abc" />;
}

function Form() {
  const handle = useRef<ClearableHandle>(null);
  return (
    <>
      <ClearableInput ref={handle} />
      <button onClick={() => handle.current?.clear()}>消去</button>
    </>
  );
}
クリック前の入力値: "abc"
クリック後の入力値: ""

親の handle.current に入るのはDOM要素ではなく、{ clear } というオブジェクトです。親ができることが clear だけに限られるので、部品の内側を変えても影響が広がりにくくなります。

refコールバックと後片付け

ref属性には、オブジェクトの代わりに関数も渡せます。要素が画面に入ったときにその要素を引数にして呼ばれ、React 19 からは戻り値として後片付けの関数を返せます。

function Cb() {
  const [show, setShow] = useState(true);
  return (
    <>
      <button onClick={() => setShow(false)}>消す</button>
      {show && (
        <p
          ref={(node) => {
            console.log("ref callback:", node?.tagName);
            return () => console.log("cleanup");
          }}
        >
          x
        </p>
      )}
    </>
  );
}
ref callback: P
cleanup

表示されたときにコールバックが、「消す」を押して要素が外れたときに後片付けの関数が呼ばれました。

リストの各要素を参照する

フックはループの中で呼べないので、行の数だけ useRef を並べることはできません。Mapを1つ ref に入れ、ref コールバックで出し入れする形にします。

function Many() {
  const map = useRef(new Map<string, HTMLLIElement>());
  const ids = ["a", "b", "c"];

  return (
    <>
      <ul>
        {ids.map((id) => (
          <li
            key={id}
            ref={(node) => {
              if (node) map.current.set(id, node);
              return () => {
                map.current.delete(id);
              };
            }}
          >
            {id}
          </li>
        ))}
      </ul>
      <button onClick={() => map.current.get("b")?.scrollIntoView()}>
        bへ移動
      </button>
    </>
  );
}

ボタンのハンドラーで Map の中身を確かめた結果です(scrollIntoView は jsdom に実装がないため、ここでは件数と中身の確認にとどめています)。

size: 3 / b の textContent: b

useRefのチェックリスト

確認すること 目安
その値は画面に出すか 出すなら useState
current を読むのはイベントかエフェクトの中か コンポーネント本体やJSXでは読まない
current が null の場合を考えているか ?. か if で確かめる
DOM参照の型は要素に合っているか input なら HTMLInputElement、初期値は null
タイマーや購読は後片付けしているか useEffect の戻り値で止める
自作コンポーネントは ref を内側の要素へ渡しているか React 19 ならpropsで受け取って渡す
表示の変更を ref で直接行っていないか 文字やクラスの変更は state とJSXで

よくある質問

Q. useRefとふつうの変数(let)は何が違いますか? A. コンポーネントの中の let は、再レンダリングのたびに初期値に戻ります。useRefの値は再レンダリングをまたいで残ります。コンポーネントの外に置いた変数は残りますが、同じコンポーネントを複数置いたときに全部で共有されます。useRefはコンポーネントの1つ1つが別々に持てます。

Q. current を書き換えたのに画面が変わりません。 A. refの書き換えは再レンダリングを起こさないためです。画面に出す値は useState に変えます。今回の確認でも、refを3回増やしても表示は 0 のままで、stateを更新した時点で 3 が表示されました。

Q. useEffect の依存配列に ref.current を入れてもよいですか? A. 入れても、current の変化では再レンダリングが起きないので、エフェクトが再実行されるきっかけになりません。要素が付いた・外れたタイミングで処理したいなら、ref コールバックを使います。

Q. forwardRef は書き換える必要がありますか? A. React 19.3.0 では forwardRef もそのまま動きました。急いで書き換える必要はありませんが、新しく書く部品は ref をpropsで受け取る形にしておくと、記述が短くなります。

まとめ

  • useRefは「書き換えても再レンダリングが起きない入れ物」。値は ref.current で読み書きする
  • 画面に出す値は useState、DOM要素や画面に出さない値は useRef
  • current が null になるのは、レンダリング中・要素が非表示・子が ref を渡していないとき
  • refを書き換えても画面は更新されない。別の再レンダリングが起きたときに表示が追い付くだけ
  • レンダリング中の読み書きは避け、イベントかエフェクトの中で行う。StrictMode で値が倍進むことを確認し、ESLintの react-hooks/refs でも検出できる
  • DOM参照の型は useRef<HTMLInputElement>(null)。React 19 の型定義では引数が必須
  • React 19 では ref をpropsとして受け取れる。forwardRef 版も 19.3.0 で動作

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「React useRefの使い方|DOM参照とuseStateとの違い」

株式会社RJCでは、ReactのuseRefとuseStateの使い分けを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?