transitionを使ってsuspend時にfallbackを表示させない
fallback表示を出さずに、
古いUIを画面に残したまま新しいUIを裏で準備して、画面を差し替えることができる
transitionを使わない時、suspendするたびにfalllbackが表示され、ちらつく
https://gyazo.com/f8f530a4189f7fd12419f917b18cf325
水色のところは下記のように、fallbackで「Loading...」を置いている
code:ts
<Suspense fallback={<div>Loading...</div>}>
<DataDisplay id={id} />
</Suspense>
with transitionでは、ロード時に、古いUIを表示し続ける
without transitionでは、ロードするたびにfallbackが表示され、画面がちらつく
code:ts
import { useState, useTransition, Suspense, use } from "react";
import "./index.css";
function App() {
const handleWithTransition = () => {
startTransition(() => {
setId((prev) => prev + 1);
});
};
const handleWithoutTransition = () => {
setId((prev) => prev + 1);
};
return (
<div className="p-8 max-w-md mx-auto">
<div className="flex gap-2 mb-4">
<button
onClick={handleWithTransition}
className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 w-48"
{isPending ? "Updating..." : "With Transition"}
</button>
<button
onClick={handleWithoutTransition}
className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 w-48"
Without Transition
</button>
</div>
<div className={transition-opacity ${isPending ? "opacity-50" : ""}}>
<Suspense
fallback={<div className="p-4 bg-gray-200 rounded">Loading...</div>}
<DataDisplay id={id} />
</Suspense>
</div>
</div>
);
}
// データ取得をシミュレート(1秒待機)
const cache = new Map<number, Promise<string>>();
const fetchData = (id: number) => {
if (!cache.has(id)) {
cache.set(
id,
new Promise<string>((resolve) =>
setTimeout(() => resolve(Data #${id}), 1000)
)
);
}
return cache.get(id)!;
};
// データ表示コンポーネント
function DataDisplay({ id }: { id: number }) {
const data = use(fetchData(id));
return <div className="p-4 bg-blue-100 rounded">Result: {data}</div>;
}