2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

非同期フローとUI反映の戦略:JavaScriptで構造化するローディング・エラー・再試行の堅牢な設計

Posted at

概要

現代のUIは非同期で動く。
ユーザーが「何かを待っている」状態に対し、ローディング表示やエラーメッセージ、再試行機能などの応答をどう設計するかが、UXの質と信頼性を決定づける

本稿では、以下の観点から非同期フローとUI設計を体系化する:

  • ローディング状態の明示と制御
  • エラーの捕捉とUI通知
  • 再試行戦略とユーザーの選択肢設計
  • 状態遷移の構造化(状態管理・フラグ・ステートマシン)
  • 抽象化による再利用可能な非同期UI構造

1. ローディング状態の構造化

✅ 明示的なローディングフラグの導入

let isLoading = false;

async function fetchData() {
  isLoading = true;
  try {
    const res = await fetch('/api/user');
    const data = await res.json();
    updateUI(data);
  } catch (e) {
    showError(e);
  } finally {
    isLoading = false;
  }
}

→ ✅ finally で必ず解除する構造に
→ ✅ フラグ名は isLoading / isSubmitting など文脈で分ける


2. エラー処理とユーザー通知

✅ try/catch + 明示的なUI表示

let errorMessage = '';

try {
  await fetchData();
} catch (e) {
  errorMessage = 'データの取得に失敗しました';
}

→ ✅ 「なぜ失敗したか」「次にどうすればいいか」を伝えるメッセージ設計が重要


3. 再試行戦略:明示的なリトライ設計

async function tryFetch(retry = 3) {
  for (let i = 0; i < retry; i++) {
    try {
      return await fetchData();
    } catch (e) {
      if (i === retry - 1) throw e;
    }
  }
}
  • ✅ 自動再試行は限定的に使う(例:ネット不安定時)
  • ✅ 明示的な再試行ボタンもUIとして用意

4. 状態モデルの設計(構造化)

const state = {
  status: 'idle', // idle | loading | success | error
  data: null,
  error: null
};

→ ✅ 状態を文字列・enumで管理すると、分岐が明示的になりUI設計が簡潔になる


5. UIコンポーネントでの非同期ハンドリング

✅ 状態に応じて描画を切り替える

if (state.status === 'loading') {
  return showSpinner();
} else if (state.status === 'error') {
  return showError(state.error);
} else if (state.status === 'success') {
  return renderData(state.data);
}

→ ✅ ロジックとUIの分離が保たれ、状態に応じたUIが意図通り動作する


6. 汎用ラッパー関数で共通化

async function withLoading(action, stateRef) {
  stateRef.status = 'loading';
  try {
    const result = await action();
    stateRef.status = 'success';
    stateRef.data = result;
  } catch (e) {
    stateRef.status = 'error';
    stateRef.error = e.message;
  }
}

→ ✅ 複数の非同期関数に共通の状態管理構造を適用可能


7. トースト通知やダイアログの設計ポイント

  • ✅ エラーは“目立つUI”で即時に伝える
  • ✅ トーストは短時間・非ブロッキングで適切
  • ✅ モーダルは「致命的エラー」や「操作が必要なとき」に限定

設計判断フロー

① 待ち時間が1秒以上ある? → ローディングUI表示

② 失敗する可能性がある? → エラーメッセージ + 再試行導線

③ 状態が複数存在する? → statusを用いた状態遷移モデルに

④ UI更新の責務が集中? → withLoadingなどで共通化

⑤ ユーザー通知は十分か? → トーストやUIメッセージで即時性を担保

よくあるミスと対策

❌ ローディング中に多重発火

→ ✅ isLoading を使ってボタンを一時無効化


❌ エラーを握り潰してユーザーに何も伝えない

→ ✅ UIにフィードバックを必ず表示する


❌ 成功・失敗でUIが更新されない

→ ✅ 状態フラグとレンダリングの紐づけを明確にする


結語

非同期フローとは「ユーザーの待ち」と「アプリケーションの応答」をつなぐ設計である。

  • 待ち時間は明示する
  • エラーは伝える
  • 成功は確実に表示する
  • 状態遷移は構造で示す
  • 複雑化したらラップして抽象化する

ユーザーにとって重要なのは、“操作に対して意味のある反応があること”。
その非同期は、意味のある設計として成立しているか?

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?