---
title: "React 19でforwardRefが不要に｜refをpropsで渡す新方式と移行手順"
url: "https://www.issoh.co.jp/tech/details/4382/"
published: 2024-12-03
updated: 2026-07-22
categories: ["React"]
publisher: "株式会社一創"
---

# React 19でforwardRefが不要に｜refをpropsで渡す新方式と移行手順

React 19では、関数コンポーネントが `ref` を通常のpropsとして受け取れるようになり、これまで必須だった `forwardRef` のラッパーが要らなくなりました。既存の `forwardRef` は後方互換のためReact 19でも動作しますが、公式は「将来のバージョンで非推奨化・削除する」と明言しています。本記事は、新しい `ref` as propの書き方、TypeScriptでの型付け、`useImperativeHandle`、React 19で追加されたrefコールバックのクリーンアップ関数、そしてReact 18コードからの移行手順（codemod）までを、実際のコードで整理します。

## まとめ：React 19のref扱いで押さえる5点

- **refがpropになった**：関数コンポーネントは `function MyInput({ ref }) {}` のように `ref` を直接受け取れる。`forwardRef` のラップは不要。
- **forwardRefは廃止予定**：React 19では動作するが、公式が将来の非推奨化・削除を予告済み。新規コンポーネントでは使わない。
- **useImperativeHandleもforwardRef不要**：`useImperativeHandle(ref, () => ({ ... }))` の第1引数にpropの `ref` をそのまま渡す。
- **TypeScriptはpropsに `ref` を含める**：`ref: Ref<HTMLInputElement>` をprops型へ追加する。
- **移行はcodemodで自動化**：`npx codemod react/19/remove-forward-ref` で既存の `forwardRef` を一括変換できる。クラスコンポーネントのrefは対象外。

## React 19でforwardRefが不要になった理由

React 18以前は、`ref` がpropsとは別枠の特殊な属性として扱われていました。親から子のDOMや公開メソッドへ参照を渡すには、コンポーネントを `forwardRef` でラップし、第2引数で受け取った `ref` を内部要素へ結線する必要がありました。ラッパーが1段挟まるぶん、コンポーネントの型定義やDevToolsの表示が一段複雑になるのが実務上の負担でした。

React 19は `ref` を関数コンポーネントの通常のpropsに格上げしました。これにより `forwardRef` の役割そのものが消え、propsの分割代入で `ref` を取り出してそのまま子要素へ渡せます。公式リリースノートは次の例を挙げています。

### React 18以前（forwardRefが必要）

```
import { forwardRef } from "react";

const MyInput = forwardRef(function MyInput(props, ref) {
  return <input placeholder={props.placeholder} ref={ref} />;
});
```

### React 19以降（refはprop）

```
function MyInput({ placeholder, ref }) {
  return <input placeholder={placeholder} ref={ref} />;
}

// 呼び出し側は変わらない
<MyInput ref={inputRef} placeholder="お名前" />
```

importから `forwardRef` が消え、関数の引数に `ref` が並ぶだけになります。ラッパー関数がなくなるため、React DevToolsのツリーにも `ForwardRef(MyInput)` ではなく `MyInput` がそのまま表示され、コンポーネントの追跡が素直になります。なお、この変更は関数コンポーネント限定です。**クラスコンポーネントに渡した `ref` は従来どおりインスタンスを指し、propsとしては渡りません。**

## refをpropsで受け取る実装とTypeScriptの型付け

`ref` がpropになったことで、TypeScriptでも「propsの一部」として型を書きます。React 18時代の `forwardRef<RefType, PropsType>` というジェネリクスは不要になり、props型に `ref` を1行足すだけです。`ref` の型は、オブジェクトrefとコールバックrefの両方を受け付ける `Ref<T>` を使います。

```
import { useRef } from "react";
import type { Ref } from "react";

type MyInputProps = {
  placeholder: string;
  ref?: Ref<HTMLInputElement>;
};

function MyInput({ placeholder, ref }: MyInputProps) {
  return <input placeholder={placeholder} ref={ref} />;
}

function Form() {
  const inputRef = useRef<HTMLInputElement>(null);
  return <MyInput ref={inputRef} placeholder="お名前" />;
}
```

`useRef<HTMLInputElement>(null)` が返す `RefObject` を、そのまま `ref` propへ渡せます。親側で `.current` にアクセスするときは、DOMがマウントされるまで `null` になり得るため `inputRef.current?.focus()` のようにオプショナルチェーンで扱います。`ref` の基礎やuseRefと`useState`の使い分けは、[ReactのuseRefの使い方（useStateとの違い・DOM参照）](https://www.issoh.co.jp/tech/details/3279/)で個別に整理しています。

## forwardRef不要で使うuseImperativeHandle

子コンポーネントが公開するメソッド（`focus()` や `scrollIntoView()` など）を親から呼びたい場合は `useImperativeHandle` を使います。React 18まではこのフックも `forwardRef` とセットでしたが、**React 19では第1引数にpropの `ref` をそのまま渡せます**。公式リファレンスも `forwardRef` なしの例に更新されています。

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

type InputHandle = { focus: () => void };

function MyInput({ ref }: { ref?: Ref<InputHandle> }) {
  const inputRef = useRef<HTMLInputElement>(null);

  useImperativeHandle(ref, () => ({
    focus() {
      inputRef.current?.focus();
    },
  }), []);

  return <input ref={inputRef} />;
}
```

公開したいAPIを `InputHandle` として定義し、`ref` の型引数に渡すことで、親側でも `ref.current?.focus()` が型安全に補完されます。内部のDOMを直接露出せず、必要な操作だけを絞って公開できるのは従来と同じで、変わったのは `forwardRef` のラッパーが消えた点だけです。

## refコールバックのクリーンアップ関数（React 19の新機能）

関数形式のref（`ref={(node) => { ... }}`）に、React 19から**クリーンアップ関数を返せる**ようになりました。`useEffect` と同じ発想で、要素がDOMから外れるときに後片付けを実行できます。サードパーティのチャートやマップなど、DOMノードに紐づくインスタンスの破棄漏れを防げます。

```
<div
  ref={(node) => {
    const chart = new HeavyChartLibrary(node);
    // NEW: クリーンアップ関数を返すと、要素の除去時に呼ばれる
    return () => {
      chart.destroy();
    };
  }}
/>
```

公式リリースノートによると、クリーンアップ関数を返した場合、**アンマウント時にRef関数が `null` で呼び出される従来の挙動はスキップされます**。クリーンアップはDOM ref・クラスコンポーネントのref・`useImperativeHandle` のいずれでも機能します。将来的にはアンマウント時に `null` でrefを呼ぶ挙動自体が非推奨になる予定です。

TypeScriptでは注意が1つあります。**ref callbackから値を暗黙に返すと、その戻り値がクリーンアップ関数と解釈されて型エラー（`element.ref` 周辺）になります。**アロー関数で1行に書くと戻り値が生まれてしまうため、副作用だけを行うrefは必ずブロック本体 `{ ... }` にして明示的に何も返さないようにします。

## React 18のforwardRefコードをReact 19へ移行する手順

既存プロジェクトの `forwardRef` は、手作業でも公式codemodでも `ref` as propへ移行できます。React公式がcodemodを提供しており、codemodレジストリ（`react/19/remove-forward-ref`）から実行できます。

### codemodによる一括変換

```
npx codemod react/19/remove-forward-ref
```

このcodemodは `forwardRef` のimportを外し、ラッパー関数を展開して、propsの分割代入に `ref` を追加します。実行後は差分をレビューし、型エラーやDevToolsの表示が想定どおりか確認してから取り込みます。コマンド名やオプションはツールの更新で変わり得るため、最新は公式の案内で確認してください。

### 手動で書き換える場合の要点

- `forwardRef(function C(props, ref) { ... })` を `function C({ ...props, ref }) { ... }` へ展開する。
- importから `forwardRef` を削除する。
- TypeScriptは `forwardRef<R, P>` のジェネリクスを外し、props型に `ref: Ref<R>` を追加する。
- `useImperativeHandle` はそのまま残し、第1引数のrefがpropになった点だけ確認する。

### 移行の判断基準と互換性

**React 19では `forwardRef` は引き続き動作します。**そのため一度に全書き換えする必要はなく、新規コンポーネントから `ref` as propで書き、既存分はcodemodで段階的に置き換える進め方が現実的です。ただし公式が非推奨化・削除を予告している以上、恒久的に `forwardRef` へ依存する設計は避けます。クラスコンポーネントに渡すrefはこの変更の対象外で、従来どおりインスタンス参照として扱う点も移行時の確認ポイントです。propsとchildrenを起点にしたコンポーネント設計の考え方は、[ReactのPropsとChildrenを活かしたコンポーネント設計](https://www.issoh.co.jp/tech/details/4116/)もあわせて参考にしてください。

## よくある質問

### React 19でforwardRefはまだ使えますか？

使えます。React 19では後方互換のため `forwardRef` は動作します。ただし公式が将来の非推奨化・削除を予告しているため、新規コンポーネントでは `ref` as propで書くことが推奨されます。

### forwardRefはいつ廃止されますか？

具体的な削除バージョンは公表されていません。リリースノートは「将来のバージョンで非推奨化し削除する」とのみ述べています。時期は未定なので、削除前提で早めに移行を進めておくのが安全です。

### useImperativeHandleにforwardRefは必要ですか？

React 19では不要です。`useImperativeHandle(ref, () => ({ ... }))` の第1引数に、propとして受け取った `ref` を直接渡せます。React 18以前は `forwardRef` の第2引数からrefを得る必要がありました。

### React 19でrefの型はどう書きますか？

props型に `ref: Ref<HTMLInputElement>` のように追加します。`forwardRef<R, P>` のジェネリクスは使いません。`Ref<T>` はオブジェクトrefとコールバックrefの両方に対応します。

### React 18と19でrefの何が変わりましたか？

関数コンポーネントで `ref` がpropsとして扱えるようになった点が最大の変化です。加えて、refコールバックからクリーンアップ関数を返せるようになり、アンマウント時の後片付けを `useEffect` なしで書けるようになりました。

## 関連記事

- [ReactのuseRefの使い方｜useStateとの違い・DOM参照・値の保持を実例で解説](https://www.issoh.co.jp/tech/details/3279/)
- [ReactのPropsとChildrenの違いを活かした効果的なコンポーネント設計](https://www.issoh.co.jp/tech/details/4116/)
- [React Compilerとは？自動メモ化の仕組みと導入方法・useMemoとの違いを解説](https://www.issoh.co.jp/tech/details/9415/)

---

出典: [React 19でforwardRefが不要に｜refをpropsで渡す新方式と移行手順](<https://www.issoh.co.jp/tech/details/4382/>)（株式会社一創）
