React v19
2024年12月5日 by The React Team
注意:React 19が安定版になりました!
4月にReact 19 RCとして最初に共有されたこの投稿以降の追加機能:
この投稿の日付は、安定版リリース日を反映するように更新されました。
React v19がnpmで利用可能になりました!
React 19アップグレードガイドでは、アプリをReact 19にアップグレードするためのステップバイステップの手順を共有しました。この投稿では、React 19の新機能の概要と、それらを採用する方法について説明します。
React 19の新機能
破壊的変更のリストについては、アップグレードガイドを参照してください。
React 19の新機能
Actions
Reactアプリでの一般的なユースケースは、データの変更を実行してから、それに応じて状態を更新することです。例えば、ユーザーが名前を変更するためにフォームを送信する場合、APIリクエストを行い、その後レスポンスを処理します。
以前は、保留状態、エラー、楽観的更新、および順次リクエストを手動で処理する必要がありました。
例えば、useStateで保留状態とエラー状態を処理できました:
function UpdateName({}) {
const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, setIsPending] = useState(false);
const handleSubmit = async () => {
setIsPending(true);
const error = await updateName(name);
setIsPending(false);
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>
);
}
React 19では、トランジションで非同期関数を使用して、保留状態、エラー、フォーム、楽観的更新を自動的に処理するサポートを追加しています。
例えば、useTransitionを使用して保留状態を処理できます:
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>
);
}
非同期トランジションは即座にisPending状態をtrueに設定し、非同期リクエストを実行し、すべてのトランジション後にisPendingをfalseに切り替えます。これにより、データが変更されている間も現在のUIを応答性があり、インタラクティブに保つことができます。
注意
慣例により、非同期トランジションを使用する関数は「Actions」と呼ばれます。
Actionsはデータの送信を自動的に管理します:
- 保留状態:Actionsはリクエストの開始時に開始し、最終的な状態更新がコミットされたときに自動的にリセットされる保留状態を提供します。
- 楽観的更新:Actionsは新しい
useOptimisticフックをサポートし、リクエストが送信されている間にユーザーに即座にフィードバックを表示できます。
- エラーハンドリング:Actionsはエラーハンドリングを提供し、リクエストが失敗したときにError Boundariesを表示し、楽観的更新を元の値に自動的に戻すことができます。
- フォーム:
<form>要素は、actionおよびformActionプロップに関数を渡すことをサポートするようになりました。actionプロップに関数を渡すと、デフォルトでActionsを使用し、送信後にフォームを自動的にリセットします。
Actionsの上に構築されて、React 19では楽観的更新を管理するuseOptimisticと、Actionsの一般的なケースを処理する新しいフックReact.useActionStateを導入しています。
react-domでは、フォームを自動的に管理する<form> Actionsと、フォーム内のActionsの一般的なケースをサポートするuseFormStatusを追加しています。
React 19では、上記の例を次のように簡略化できます:
function ChangeName({ name, setName }) {
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await updateName(formData.get("name"));
if (error) {
return error;
}
redirect("/path");
return null;
},
null,
);
return (
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>Update</button>
{error && <p>{error}</p>}
</form>
);
}
次のセクションでは、React 19の新しいAction機能のそれぞれを詳しく説明します。
新しいフック:useActionState
Actionsの一般的なケースを簡単にするために、useActionStateという新しいフックを追加しました:
const [error, submitAction, isPending] = useActionState(
async (previousState, newName) => {
const error = await updateName(newName);
if (error) {
return error;
}
return null;
},
null,
);
useActionStateは関数(「Action」)を受け取り、呼び出すラップされたActionを返します。これはActionsが合成されるため機能します。ラップされたActionが呼び出されると、useActionStateはActionの最後の結果をdataとして、Actionの保留状態をpendingとして返します。
注意
React.useActionStateは、Canaryリリースでは以前ReactDOM.useFormStateと呼ばれていましたが、名前を変更し、useFormStateを非推奨にしました。詳細については#28491を参照してください。
詳細については、useActionStateのドキュメントを参照してください。
React DOM:<form> Actions
Actionsは、react-domのReact 19の新しい<form>機能とも統合されています。<form>、<input>、<button>要素のactionおよびformActionプロップに関数を渡して、Actionsでフォームを自動的に送信するサポートを追加しました:
<form action={actionFunction}>
<form> Actionが成功すると、Reactは制御されていないコンポーネントのフォームを自動的にリセットします。<form>を手動でリセットする必要がある場合は、新しいrequestFormReset React DOM APIを呼び出すことができます。
詳細については、<form>、<input>、<button>のreact-domドキュメントを参照してください。
React DOM:新しいフック:useFormStatus
デザインシステムでは、プロップをコンポーネントにドリルダウンすることなく、含まれている<form>に関する情報にアクセスする必要があるデザインコンポーネントを書くことが一般的です。これはContextを介して行うことができますが、一般的なケースを簡単にするために、新しいフックuseFormStatusを追加しました:
import { useFormStatus } from 'react-dom';
function DesignButton() {
const { pending } = useFormStatus();
return <button type="submit" disabled={pending} />
}
useFormStatusは、フォームがContextプロバイダーであるかのように、親<form>のステータスを読み取ります。
詳細については、useFormStatusのreact-domドキュメントを参照してください。
新しいフック:useOptimistic
データ変更を実行するときの別の一般的なUIパターンは、非同期リクエストが進行中の間に最終状態を楽観的に表示することです。React 19では、これを簡単にするためにuseOptimisticという新しいフックを追加しています:
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>
);
}
useOptimisticフックは、updateNameリクエストが進行中の間、即座にoptimisticNameをレンダリングします。更新が完了するかエラーが発生すると、Reactは自動的にcurrentName値に戻ります。
詳細については、useOptimisticのドキュメントを参照してください。
新しいAPI:use
React 19では、レンダー中にリソースを読み取るための新しいAPI useを導入しています。例えば、useでpromiseを読み取ることができ、ReactはpromiseがresolveするまでSuspendします:
import { use } from 'react';
function Comments({ commentsPromise }) {
const comments = use(commentsPromise);
return comments.map(comment => <p key={comment.id}>{comment}</p>);
}
function Page({ commentsPromise }) {
return (
<Suspense fallback={<div>Loading...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
)
}
注意
useはレンダー中に作成されたpromiseをサポートしません。レンダー中に作成されたpromiseをuseに渡そうとすると、Reactは警告します:
コンソール
コンポーネントがキャッシュされていないpromiseによってsuspendされました。Suspense互換のライブラリまたはフレームワーク以外では、クライアントコンポーネントまたはフック内でpromiseを作成することはまだサポートされていません。
修正するには、promiseのキャッシングをサポートするSuspense対応のライブラリまたはフレームワークからpromiseを渡す必要があります。将来的には、レンダー中でpromiseをキャッシュしやすくする機能を提供する予定です。
useでContextを読み取ることもでき、早期リターン後などの条件付きでContextを読み取ることができます:
import { use } from 'react';
import ThemeContext from './ThemeContext'
function Heading({ children }) {
if (children == null) {
return null;
}
const theme = use(ThemeContext);
return (
<h1 style={{ color: theme.color }}>
{children}
</h1>
);
}
use APIは、フックと同様にレンダー中にのみ呼び出すことができます。フックとは異なり、useは条件付きで呼び出すことができます。将来的には、useでレンダー中にリソースを消費するより多くの方法をサポートする予定です。
詳細については、useのドキュメントを参照してください。
新しいReact DOM静的API
静的サイト生成のために、react-dom/staticに2つの新しいAPIを追加しました:
prerender
prerenderToNodeStream
これらの新しいAPIは、静的HTML生成のためにデータの読み込みを待機することでrenderToStringを改善します。これらは、Node.js StreamsやWeb Streamsなどのストリーミング環境で動作するように設計されています。
例えば、Web Stream環境では、prerenderを使用してReactツリーを静的HTMLにプリレンダリングできます:
import { prerender } from 'react-dom/static';
async function handler(request) {
const { prelude } = await prerender(<App />, {
bootstrapScripts: ['/main.js']
});
return new Response(prelude, {
headers: { 'content-type': 'text/html' },
});
}
Prerender APIは、静的HTMLストリームを返す前にすべてのデータが読み込まれるまで待機します。ストリームは文字列に変換したり、ストリーミングレスポンスで送信したりできます。これらは、既存のReact DOMサーバーレンダリングAPIでサポートされている、読み込み時のストリーミングコンテンツをサポートしません。
詳細については、React DOM静的APIを参照してください。
React Server Components
Server Components
Server Componentsは、クライアントアプリケーションやSSRサーバーとは別の環境で、バンドル前に事前にコンポーネントをレンダリングできる新しいオプションです。この別の環境がReact Server Componentsの「サーバー」です。Server ComponentsはCIサーバーでビルド時に一度実行することも、Webサーバーを使用してリクエストごとに実行することもできます。
React 19には、CanaryチャンネルからのすべてのReact Server Components機能が含まれています。これは、Server Compo