charging-cabinet/software/h5-uniapp/agent/skills/vue-best-practices/reference/suspense-fallback-not-immediate-on-revert.md
12451 b553c4e519 feat: API 统一 + 设备详情补全 + H5 导航优化
- API 路由统一: 移除 /api/h5/,统一 /api/pms/ 入口
- 二进制改名: api-server -> pms-api(与服务名一致)
- nginx: 合并 /api/ + /pms/api/ 为 /api/pms/
- 新增 docs/API.md 接口文档
- 后端: CabinetDetail 增加 rssi/pow_fail/address/soc 等字段
- Redis 管道批量读取仓体实时数据(SOC/电压/电流/功率)
- DB: 所有 TIMESTAMP 列改为 DATETIME(修复类型不匹配)
- 用户管理: 新增创建时间/修改时间列,状态改用 Switch
- 角色管理/用户管理: 操作按钮改为图标
- PC 设备详情: 基本信息补全 RSSI/ICCID/电源/地址
- PC 卡片: 通道统计改用 Lucide 图标,颜色统一
- PC 二维码: canvas 渲染,含编号文字,支持右键下载
- H5: 按 uni-app 规范修正导航(navigateTo 替代 reLaunch)
- H5: 详情页加返回导航条
- H5: 扫码支持摄像头(jsQR)+ ?id= 参数
- H5: 底部 tabBar 在所有页面常显
- H5: 首页统计改为 6 项(设备/通道/空闲/充电/充满/故障)
- H5: 下拉刷新 / 上拉加载
- 产品首页: 添加业务联系
- 文档: 清理过时文件,补充缺失规范章节
2026-07-04 04:03:02 +08:00

3.3 KiB

Suspense Fallback Not Immediately Shown on Revert

Rule

When Suspense reverts from resolved to pending state, the fallback content is NOT immediately displayed. Instead, the previous #default content remains visible while waiting for new content to resolve. Use the timeout prop to control when the fallback appears.

Why This Matters

This behavior prevents UI flicker for fast async operations, but can confuse users when loading takes longer than expected. Without understanding this, developers may think their fallback content is broken or Suspense isn't working correctly.

Bad Code

<template>
  <!-- Fallback won't show immediately when content changes -->
  <Suspense>
    <component :is="currentView" :key="viewKey" />

    <template #fallback>
      <!-- This may never appear for fast loads -->
      <LoadingSpinner />
    </template>
  </Suspense>
</template>

Good Code

Solution 1: Use timeout="0" for Immediate Fallback

<template>
  <!-- Fallback shows immediately on any pending state -->
  <Suspense timeout="0">
    <component :is="currentView" :key="viewKey" />

    <template #fallback>
      <LoadingSpinner />
    </template>
  </Suspense>
</template>

Solution 2: Use Appropriate Timeout for UX Balance

<template>
  <!-- Wait 200ms before showing fallback to avoid flicker on fast loads -->
  <Suspense :timeout="200">
    <component :is="currentView" :key="viewKey" />

    <template #fallback>
      <LoadingSpinner />
    </template>
  </Suspense>
</template>

Solution 3: Use Transitions for Smooth State Changes

<template>
  <RouterView v-slot="{ Component }">
    <template v-if="Component">
      <Transition mode="out-in">
        <Suspense :timeout="100">
          <component :is="Component" />

          <template #fallback>
            <div class="route-loading">
              <LoadingSpinner />
            </div>
          </template>
        </Suspense>
      </Transition>
    </template>
  </RouterView>
</template>

Timeout Behavior Summary

Timeout Value Behavior
Not specified Previous content shown until new content resolves (no fallback on revert)
timeout="0" Fallback shown immediately when entering pending state
timeout="200" Wait 200ms, then show fallback if still pending

When to Use Each Approach

No timeout (default):

  • When async operations are typically fast (<100ms)
  • When showing stale content is acceptable during loading
  • To prevent flicker on quick navigation

timeout="0":

  • When you always want to show loading feedback
  • For operations that typically take noticeable time
  • When stale content would be confusing

timeout with delay (e.g., 200ms):

  • Best of both worlds for most cases
  • Avoids flicker for fast loads
  • Still shows loading for slower operations

Key Points

  1. Default Suspense behavior prioritizes showing stale content over fallback
  2. Use timeout="0" if you always want the loading indicator
  3. Choose timeout values based on expected async operation duration
  4. Combine with <Transition> for smoother state changes
  5. This behavior is by design to improve perceived performance

References