React 18から導入されたuseTransitionフックは、UIの応答性を保ちながら非同期処理を扱える強力なツールです。
検索フォームやフィルター機能など、重たい再レンダリングが発生する場面で特に効果を発揮します。
この記事では、useTransitionを使ったUIパフォーマンス最適化の手法と、従来の状態管理との違いを実際のコードで紹介します。
useTransitionとは?
useTransitionフックを使うと、状態の更新に優先順位をつけることができます。これにより、UIの即時反応(クリック、入力など)は保ちつつ、重い処理は「低優先」で遅れて実行されるようになります。
const [isPending, startTransition] = useTransition();
・isPending: 非同期状態のフラグ。UI側でスピナーなどを制御するのに使います。
・startTransition(callback): 指定した更新処理を低優先としてスケジュールします。
従来の実装(useStateのみ)
以下のように検索ボックスに入力するたびにsetSearchResults()を呼び出すと、検索結果の描画に時間がかかるとUIが固まることがあります。
import { useState } from "react";
function SearchComponent({ searchData }: { searchData: string[] }) {
const [query, setQuery] = useState("");
const [results, setResults] = useState<string[]>([]);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setQuery(value);
const filtered = searchData.filter((item) => item.includes(value));
setResults(filtered);
};
return (
<div>
<input value={query} onChange={handleChange} placeholder="検索" />
<ul>
{results.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</div>
);
}
useTransitionを使った改善
以下のようにstartTransitionを使うことで、重たいsetResults()を低優先度にして、UIの応答性を保つことができます。
import { useState, useTransition } from "react";
function SearchComponent({ searchData }: { searchData: string[] }) {
const [query, setQuery] = useState("");
const [results, setResults] = useState<string[]>([]);
const [isPending, startTransition] = useTransition();
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setQuery(value);
startTransition(() => {
const filtered = searchData.filter((item) => item.includes(value));
setResults(filtered);
});
};
return (
<div>
<input value={query} onChange={handleChange} placeholder="検索" />
{isPending && <p>読み込み中...</p>}
<ul>
{results.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</div>
);
}
主な改善点
・応答性の向上:重いレンダリングが入力応答を妨げなくなる。UX向上。
・保留状態の表示:isPending で「読み込み中」などのUIが制御できる。
・コードの明確化:非同期・低優先の処理が明確に分離されて読みやすくなる。
まとめ
useTransitionは、ReactアプリのパフォーマンスとUXを改善する非常に効果的な手段です。特に以下のような場面での導入をおすすめします:
・フィルターや検索などの再描画が重い処理
・クライアント側でデータを大量に扱うページ
・入力やクリック応答がカクついている箇所
React 18以降を利用しているプロジェクトでは、ぜひ一度useTransitionを取り入れてみてください。