この記事の対象読者
- APIの読み込み中表示を実装する人
- スピナーだけでよいのか迷っている人
- 業務画面で「今どういう状態か」を分かりやすく見せたい人
本題に入る前に
業務画面を使っていると、検索ボタンを押したあとに少し待つ場面があります。
一覧を読み込む、外部サービスと同期する、CSVを取り込む、集計結果を出す。どれも裏側では時間がかかることがあります。
このとき、画面が何も変わらないと「押せていないのかな?」と不安になりますよね。。そしてもう一度押したり、ページを更新したりして、かえって処理が増えることもあります。
読み込み中UIは、ただの飾りではありません。ユーザーに「今ちゃんと処理しています」と伝えるための大事な状態表示です。
この記事では、Reactで読み込み中、空、失敗、成功を分けて見せる小さな考え方をまとめます。
まず状態を4つに分ける
読み込み中の画面を考えるときは、最初に状態を分けると楽です。
| 状態 | 画面で伝えたいこと |
|---|---|
| loading | 今読み込んでいる |
| empty | 読み込みは終わったがデータがない |
| error | 読み込みに失敗した |
| success | データを表示できる |
「まだ読み込み中」と「0件でした」は見た目が似てしまうことがありますが、意味は全然違います。
最小のReact例
status を文字列で持つと、画面の状態を整理しやすくなります。
type Reservation = {
id: string;
title: string;
};
type LoadStatus = "idle" | "loading" | "success" | "empty" | "error";
export function ReservationList() {
const [status, setStatus] = useState<LoadStatus>("idle");
const [items, setItems] = useState<Reservation[]>([]);
async function load() {
setStatus("loading");
try {
const response = await fetch("/api/reservations");
const data = (await response.json()) as Reservation[];
setItems(data);
setStatus(data.length === 0 ? "empty" : "success");
} catch {
setStatus("error");
}
}
useEffect(() => {
load();
}, []);
if (status === "loading") {
return <p>予約を読み込んでいます...</p>;
}
if (status === "error") {
return (
<div>
<p>予約を読み込めませんでした。</p>
<button type="button" onClick={load}>再読み込み</button>
</div>
);
}
if (status === "empty") {
return <p>条件に一致する予約はありません。</p>;
}
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
);
}
スピナーだけでは足りないことがある
スピナーは便利ですが、それだけだと「何を待っているのか」が分かりません。
業務画面では、次のように少し具体的な文言にすると親切です。
| あいまいな表示 | 少し親切な表示 |
|---|---|
| 読み込み中 | 予約一覧を読み込んでいます |
| 処理中 | CSVを取り込んでいます |
| しばらくお待ちください | 集計結果を作成しています |
ほんの少し具体的にするだけで、待っている側の不安が減ります。
長くかかる処理は段階を見せる
検索や一覧取得なら「読み込み中」で十分なことが多いです。
でも、CSV取り込みや外部サービス同期のように数十秒かかる可能性がある処理では、もう少し情報がほしくなります。
CSVを取り込んでいます
現在 120 / 1,000 行を確認中です
ここまで出せない場合でも、「画面を閉じずにお待ちください」「完了後に結果を表示します」のように、次に何が起きるかを書くと安心できます。
まとめ
読み込み中UIは、ユーザーを待たせるためのものではなく、待っている時間を不安にしないためのものです。
最初は loading / empty / error / success を分けるだけで十分です。状態が分かれると、文言もコードも整理しやすくなります。