React19へのアップデートがあったので、ドキュメントを読んで簡単に新機能まとめて整理してみました。
React18までの課題
送信中(pending)の状態管理
ボタンの無効化やローディングスピナー表示のためにuseStateを用いて「送信中」の状態を管理。
エラー発生時の処理
非同期リクエストが失敗した場合、適切なエラーメッセージをユーザーに表示する処理を追加。
楽観的更新
サーバーにリクエストを送信する前にUIを更新し。エラー発生時には元に戻す処理を手動で実装。
複数リクエストの順序管理
非同期リクエストが複数発生した際に順序を正しく保つためのロジックを実装しなければいけない。
React19
React19では、上記の「送信中の状態」「エラー処理」「成功時の画面更新」などの状態管理を簡略化するための仕組みが強化された。
また、エラーが発生した場合は自動的に状態をロールバックする仕組みが組み込まれるようになった。
状態管理が自動化
React19では、「送信中の状態」「エラー処理」「成功時の画面更新」といった状態管理を簡略化するための仕組みが強化されました。これにより、状態管理のためのコードが大幅に削減できます。
新しいhooksの追加と機能まとめ
・useActionState:アクションの一般的なユースケースを簡単に実現するためのhooks。第一引数には非同期関数(アクション)を記述してその結果やエラーを管理する。第二引数にはアクションの初期状態を指定する。
状態(成功・失敗・エラーなど)とアクションを一つのhooksで扱うことができうため、コードが見通しやすくなる(大規模なコンポーネントでも状態管理が煩雑になりにくい)
・useFormStatus:HTMLフォームと連携し、フォーム送信の状態を管理するために使用される。これによってフォームの送信中の状態(pending)、エラー、成功状態などを簡単に追跡することができる。
・useOptimistic:サーバーリクエストの結果を待つことなく、UIを先に更新する手法(以下に使い方を記載)
Reac18のコード例
function UpdateName(){
//入力された名前を保持する
const[name,setName]=useState('');
//エラーが発生した場合にその内容を保持する
const[error,setError]=useState(null);
//非同期処理中かどうかを示す
const[isPending,setIsPending]=useState(false);
const handleSubmit=async()=>{
setIsPending(true);
setError(null);
try{
await updateName(name);
console.log('update successful');
}catch(e){
setError(e.message);
}finally{
setIsPending(false);
}
}
return(
<div>
<input value={name} onChange={(e)=>setName(e.target.value)}/>
<button onClick={handleSubmit} disabled={isPending}>
{isPending?'Updating...':'Update'}
</button>
{error&& <p style={{color:'red'}}>{error}</p>}
</div>
);
}
Reac19のコード例
function UpdateName(){
//第一引数は初期値、第二引数はアップデートの際に実行する関数
const[optimisticName,setOptimisticName]
=useOptimistic('',
(currentValue,newValue)=>newValue);
//非同期処理関数
const handleSubmit=async()=>{
//現在の名前の状態を即座に更新、UIに反映
try{ setOptimisticName(optimisticName);
//非同期でサーバーに名前を更新するリクエストを送信する
//この間にサーバーからの応答を待機する
await updateName(optimisticName);
console.log('名前の更新に成功しました');
}catch(error){
console.error('名前の更新に失敗しました',error);
setError('名前の更新に失敗しました。もう一度お試しください')
}
};
return(
<div>
<input
value={optimisticName}
onChange={(e)=>setOptimisticName(e.target.value)}
/>
<button onClick={handleSubmit}>
Update
</button>
{error && <p style={{ color: "red" }}>{error}</p>}
</div>
);
}
//JSX構造
return(
<div>
<input
value={optimisticName}
onChange={(e)=>setOptimisticName(e.target.value)}
/>
<button onClick={handleSubmit}>Update</button>
</div>
)