React 19 まとめ（日本語）

# 概要

2024年12月6日（金）に React 19 が発表されたので、内容をまとめます

## アクションの導入

:::message
非同期トランジションを使用する関数を規約として「アクション」と呼ぶ
と React v19 のブログの中で定義されていたので同じ言葉を使用しています
:::

React 18 から導入された useTransition hooks の返り値である `startTransition` のコールバック関数の中で async await を使用した非同期関数が使用できるようになリました

React v18 では、使用することができませんでした。（[詳細はこちら](https://ja.react.dev/reference/react/useTransition#react-doesnt-treat-my-state-update-as-a-transition)）
※ 以下スクリーンショット、公式ドキュメントから抜粋

![](https://storage.googleapis.com/zenn-user-upload/f0bc36f575ad-20241206.png)

```ts
// React v18
// ❌ Setting state *after* startTransition call
startTransition(async () => {
  await someAsyncFunction();
  setPage('/about');
});

// React v19
// ✅ Setting state *after* startTransition call
startTransition(async () => {
  await someAsyncFunction();
  setPage('/about');
});
```

## 新しいフックの追加

アクションの仕組みを土台として
react と react-dom に新たなフックが追加されました。

- react
    - useOptimistic: 楽観的なUI更新を簡単に実装するためのフック
    - useActionState: アクションの結果に基づいて状態を更新するためのフック
- react-dom
    - useFormStatus: フォームの送信状態（送信中、エラーなど）を追跡するためのフック

## フォーム要素の強化

<form>要素の action属性 に関数を直接渡すことが可能になり、フォーム送信時の処理がより柔軟になりました。<form>、<input>、<button> の各要素において、props である action および formAction に関数を渡すことがサポートされるようになりました。これによりアクションを用いて自動的にフォームの送信が可能です。

```html
<form action={actionFunction}>
```

<form> アクションが成功すると、React は非制御コンポーネントの場合にフォームを自動的にリセットします。手動で <form> をリセットする必要がある場合は、新しい React DOM の API である requestFormReset を呼び出すことができます。

## 新しいAPI `use` の導入

React 19 では、レンダー中にリソースを読み取るための新しい API である use を導入しています。たとえば、use でプロミスを読み取ることができます。プロミスが解決 (resolve) するまで React はサスペンドします。use API は、フックと同様にレンダー中にのみ呼び出すことができます。しかしフックとは異なり、use は条件分岐の中でも呼び出すことが可能です。将来的には、use を使用してレンダー中にリソースを使用する方法をさらに拡充する予定です。

```tsx
import { use } from 'react';

function Comments({commentsPromise}) {
  // `use` will suspend until the promise resolves.
  const comments = use(commentsPromise);
  return comments.map(comment => <p key={comment.id}>{comment}</p>);
}

function Page({commentsPromise}) {
  // When `use` suspends in Comments,
  // this Suspense boundary will be shown.
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Comments commentsPromise={commentsPromise} />
    </Suspense>
  )
}
```

## ref が props として渡せるように

React 19 から、関数コンポーネントにおいて ref に props としてアクセスできるようになりました。なので、新しいコンポーネントでは `forwardRef` が不要になります。将来のバージョンでは `forwardRef` は非推奨となり削除される予定です。

### React 18 まで

```tsx
import React, { forwardRef } from 'react';

type Props = {
  placeholder?: string
}

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

//...
<MyInput ref={ref} />
```

### React 19

```tsx
import React, { forwardRef } from 'react';

type Props = {
  placeholder?: string
  ref: RefObject<HTMLInputElement>
}

const MyInput = (props: Props) => {
  return <input placeholder={props.placeholder} ref={props.ref} />;
});

//...
<MyInput ref={ref} />
```

## Context が Provider に

`<Context.Provider>` の代わりに `<Context>` をプロバイダとしてレンダーできるようになりました。

### React 18 まで

```tsx
const ThemeContext = createContext('');

function App({children}) {
  return (
    <ThemeContext.Provider value="dark">
      {children}
    </ThemeContext.Provider>
  );  
}
```

### React 19

```tsx
const ThemeContext = createContext('');

function App({children}) {
  return (
    <ThemeContext value="dark">
      {children}
    </ThemeContext>
  );  
}
```

## 最後に

これで Next.js 15 も Stable になったし、React の 19 も Stable になりましたね

# 参考文献

https://ja.react.dev/blog/2024/04/25/react-19
https://react.dev/blog/2024/12/05/react-19