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

4.7 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Choose watch vs watchEffect Based on Dependency Control Needs MEDIUM Wrong choice leads to unnecessary re-runs or missed dependency tracking efficiency
vue3
watch
watchEffect
watchers
reactivity
best-practices

Choose watch vs watchEffect Based on Dependency Control Needs

Impact: MEDIUM - Using watch when watchEffect would be cleaner leads to repetitive code. Using watchEffect when watch is needed can cause unexpected re-runs or missed dependencies (especially with async).

Use watchEffect for simple cases where the callback uses the same state as what should trigger it. Use watch when you need precise control over what triggers the callback, access to old values, or lazy execution.

Task Checklist

  • Use watchEffect when callback logic uses the same state it should react to
  • Use watch when you need old value comparison
  • Use watch when you need lazy execution (not immediate)
  • Use watch for async callbacks with dependencies after await
  • Use watch when callback should not run on initial mount

Comparison Table

Feature watch watchEffect
Dependency tracking Explicit (you specify) Automatic (uses accessed properties)
Lazy by default Yes (runs only on change) No (runs immediately)
Access old value Yes No
Async dependency tracking Full control Only before first await
Multiple sources Array syntax Automatic

When to prefer watchEffect:

<script setup>
import { ref, watchEffect } from 'vue'

const todoId = ref(1)
const data = ref(null)

// GOOD: watchEffect is cleaner when callback uses same state
watchEffect(async () => {
  const response = await fetch(
    `https://api.example.com/todos/${todoId.value}`
  )
  data.value = await response.json()
})
</script>

When to prefer watch:

<script setup>
import { ref, watch } from 'vue'

const todoId = ref(1)
const data = ref(null)

// BETTER with watch when:

// 1. You need old value
watch(todoId, (newId, oldId) => {
  console.log(`Changed from ${oldId} to ${newId}`)
})

// 2. You don't want immediate execution
watch(todoId, () => {
  // Only runs when todoId changes, not on mount
  fetchData()
})

// 3. You have dependencies after await
watch(todoId, async (id) => {
  const response = await fetch(`/api/todos/${id}`)
  // More reactive access here still triggers correctly
  // because we explicitly specified todoId as the source
})
</script>

Avoid Redundant Code with watchEffect

<script setup>
import { ref, watch, watchEffect } from 'vue'

const searchQuery = ref('')
const category = ref('all')
const results = ref([])

// BAD: Repetitive - listing same deps in source and using in callback
watch(
  [searchQuery, category],
  ([query, cat]) => {
    fetchResults(query, cat)  // Same variables repeated
  }
)

// GOOD: watchEffect removes repetition
watchEffect(() => {
  fetchResults(searchQuery.value, category.value)
})
</script>

Use watch for Lazy Behavior

<script setup>
import { ref, watch, watchEffect } from 'vue'

const userId = ref(null)

// BAD: Runs immediately even when userId is null
watchEffect(() => {
  if (userId.value) {
    loadUserProfile(userId.value)
  }
})

// GOOD: Only runs when userId actually changes
watch(userId, (id) => {
  if (id) {
    loadUserProfile(id)
  }
})

// ALSO GOOD: watch with immediate when you need both behaviors
watch(
  userId,
  (id) => {
    if (id) loadUserProfile(id)
  },
  { immediate: true }  // Explicit about running immediately
)
</script>

Use watch for Old Value Comparison

<script setup>
import { ref, watch } from 'vue'

const status = ref('pending')

// Only watch() provides old value
watch(status, (newStatus, oldStatus) => {
  if (oldStatus === 'pending' && newStatus === 'approved') {
    showApprovalNotification()
  }

  if (oldStatus === 'approved' && newStatus === 'rejected') {
    showRejectionWarning()
  }
})
</script>

Use watch for Complex Async Dependencies

<script setup>
import { ref, watch } from 'vue'

const filters = ref({ status: 'active', sort: 'date' })
const page = ref(1)
const results = ref([])

// BETTER: watch with explicit sources for async
// All dependencies tracked regardless of await placement
watch(
  [filters, page],
  async ([currentFilters, currentPage]) => {
    const data = await fetchWithFilters(currentFilters)

    // These are still correctly tracked:
    results.value = paginateResults(data, currentPage)
  },
  { deep: true }
)
</script>

Reference