サーバーコンポーネント、use による Promise の読み取り、そして React 19 の楽観的更新を探ります。
このレッスンを Kodokon で開くReact Server Components(RSC)はクライアントとサーバーの境界を引き直します。サーバーコンポーネントは サーバー上でのみ 実行されます。そのコードはクライアントバンドルに一切届かず、async にでき、データベースやファイルシステムを直接読み取ることができ、その出力は React がクライアントツリーとマージする シリアライズされたストリーム(RSC ペイロード)としてブラウザに送信されます。その代わり、state もエフェクトもブラウザへのアクセスもありません。useState も useEffect もイベントハンドラーもありません。クライアント上で再レンダーされることは決してありません。
// Server component: never sent to the client.
export default async function NotesPage() {
const notes = await db.notes.findAll();
return (
<ul>
{notes.map((note) => (
<li key={note.id}>{note.title}</li>
))}
</ul>
);
}インタラクティビティは クライアントコンポーネント に存在し、ファイル先頭の 'use client' ディレクティブでマークされます。このディレクティブは「クライアントコンポーネント」をマークするのではなく 境界 をマークします。そのモジュールがインポートするものはすべて、同様にクライアント側へ移ります。境界を越える props は シリアライズ可能 でなければなりません。プレーンなオブジェクト、配列、Promise などは可能ですが、通常の関数やクラスのインスタンスは決して渡せません。
'use client';
import { useState } from 'react';
export function LikeButton({ initialCount }) {
const [count, setCount] = useState(initialCount);
return (
<button onClick={() => setCount(count + 1)}>
{count} likes
</button>
);
}React 19 は use を導入します。これは Promise または コンテキスト の値を読み取る API です。フックとは異なり、use は 条件やループの内部で 呼び出せます。Promise を渡された場合、解決までコンポーネントをサスペンドし、最も近い Suspense 境界に依存します。慣用的なパターン: サーバーコンポーネントが await せずに Promise を 生成 し、それを prop として渡し、クライアントコンポーネントが use でそれを 消費 します。こうすることで、サーバーはデータを待たずにページのストリーミングを開始できます。
import { use, Suspense } from 'react';
function Comments({ commentsPromise }) {
const comments = use(commentsPromise);
return comments.map((c) => (
<p key={c.id}>{c.text}</p>
));
}
function Page({ commentsPromise }) {
return (
<Suspense fallback={<Spinner />}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
);
}インタラクション側では、useTransition が更新を非緊急としてマークし、isPending を公開するので、入力をブロックせずに控えめなインジケーターを表示できます。useOptimistic はネットワークミューテーションのためにこのデュオを完成させます。非同期アクションが実行される間、期待される state を即座に表示し、アクションが終わると(成功でも失敗でも)、React は 楽観的な値を破棄 し、信頼できる情報源からの実際の state を再び表示します。
const [optimisticLikes, addOptimisticLike] =
useOptimistic(likes, (count, delta) => count + delta);
function handleLike() {
startTransition(async () => {
addOptimisticLike(1);
await saveLike();
// At the end, React shows the real state again.
});
}use API が破ってよいフックのルールはどれですか?useOptimistic の値はどうなりますか?