React v19の新機能

# 概要
2024年12月5日（木）に React 19 が発表されたので、内容をまとめます。

### 主な新機能

#### アクション (Action)
データの書き換えと状態更新を簡素化する新機能です。非同期関数をトランジション内で使用することで、送信中状態、エラー処理、楽観的更新を自動的に管理します。

**useTransition**
トランジション内で非同期関数を使用することで、送信中状態、エラー、フォーム、楽観的更新を自動的に処理するためのサポートが追加されました。
```ts
// Using pending state from Actions
function UpdateName({}) {
  const [name, setName] = useState("");
  const [error, setError] = useState(null);
  const [isPending, startTransition] = useTransition();

  const handleSubmit = () => {
    startTransition(async () => {
      const error = await updateName(name);
      if (error) {
        setError(error);
        return;
      } 
      redirect("/path");
    })
  };

  return (
    <div>
      <input value={name} onChange={(event) => setName(event.target.value)} />
      <button onClick={handleSubmit} disabled={isPending}>
        Update
      </button>
      {error && <p>{error}</p>}
    </div>
  );
}
```

#### 新しいフック
**useActionState**
アクションの一般的なユースケースを簡単に実現するためのフックです。
```ts
const [error, submitAction, isPending] = useActionState(
  async (previousState, newName) => {
    const error = await updateName(newName);
    if (error) {
      // You can return any result of the action.
      // Here, we return only the error.
      return error;
    }

    // handle success
    return null;
  },
  null,
);
```
アクションをラップしたものが返されます。ラップされたアクションが呼び出されると、useActionState はアクションの最終結果を `data` として、アクションの進行中状態を `pending` として返します。

:::note info
useActionStateは以前のリリースではuseFormStateと呼ばれていましたが、
名前が変更され、useFormStateは非推奨になったようです。
:::

**useOptimistic**
非同期リクエスト中に楽観的な状態更新を行うためのフックです。
```ts
function ChangeName({currentName, onUpdateName}) {
  const [optimisticName, setOptimisticName] = useOptimistic(currentName);

  const submitAction = async formData => {
    const newName = formData.get("name");
    setOptimisticName(newName);
    const updatedName = await updateName(newName);
    onUpdateName(updatedName);
  };

  return (
    <form action={submitAction}>
      <p>Your name is: {optimisticName}</p>
      <p>
        <label>Change Name:</label>
        <input
          type="text"
          name="name"
          disabled={currentName !== optimisticName}
        />
      </p>
    </form>
  );
}
```
`updateName`リクエストが進行中になると、`optimisticName`を即座にレンダリングします。
更新が完了するかエラーが発生すると、自動的に `currentName`の値に戻します。

**useFormStatus (React DOM)**
フォームの状態にアクセスするためのフックです。
```ts
import {useFormStatus} from 'react-dom';

function DesignButton() {
  const {pending} = useFormStatus();
  return <button type="submit" disabled={pending} />
}
```
`useFormStatus`を使うことで、親フォーム自体がコンテキストプロバイダのように、親`<form>`の状態を読み取れます。

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

#### 新しいAPI `use`
レンダリング中にリソースを読み取るための新しいAPIである`use`が導入されました。
`use`でプロミスを読み取り、プロミスが解決`resolve`するまでsuspendされます。

```ts
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 に
関数コンポーネントにおいて ref に props としてアクセスできるようになりました。
```ts
function MyInput({placeholder, ref}) {
  return <input placeholder={placeholder} ref={ref} />
}

//...
<MyInput ref={ref} />
```
新しい関数コンポーネントでは `forwardRef` が不要になります。新しい `props` である `ref` を使用するようコンポーネントを自動的に更新する codemod が公開される予定です。将来のバージョンでは `forwardRef` は非推奨となり、削除されます。

:::note warn
クラスに渡された ref はコンポーネントインスタンスを参照するため、props としては渡されません。
:::

#### `<Context>` がプロバイダに
React 19 では、<Context.Provider> の代わりに <Context> をプロバイダとしてレンダーできるようになりました。
```ts
const ThemeContext = createContext('');

function App({children}) {
  return (
    <ThemeContext value="dark">
      {children}
    </ThemeContext>
  );  
}
```
新しいコンテクストプロバイダは <Context> のように使用できるため、既存のプロバイダを変換するための codemodが公開される予定です。将来のバージョンでは <Context.Provider> は非推奨になる予定です。

### 最後に
今回のバージョンアップでは便利な機能がいくつも追加されたと感じます。
今後の更なるアップデートにも注目していきたいです。

#### 参考
https://react.dev/blog/2024/12/05/react-19