← 中文资源

简体中文版本

Vue 数组变更不响应 — UI 不更新

通过替换数组或使用可响应的方法,并避免直接修改索引位置,修复 Vue 数组更新不响应的问题。

阅读英文原文

症状

遇到“Vue 数组变更不响应 — UI 不更新”时靠猜测只会浪费时间。请按证据排查:先复现症状,再执行针对性诊断,定位根因后修复,并用明确检查验证结果。

可观察到的症状包括:

  • 向数组 push 后 UI 不更新
  • 按下标赋值(arr[0] = x)不重渲染
  • 修改数组长度不触发更新

诊断

先在隔离环境中复现故障,再按顺序执行以下检查,逐步缩小范围。

步骤 1

import { isReactive } from 'vue'; console.log(isReactive(arr));

若为 false,说明数组被复制或在响应式上下文外创建。

步骤 2

arr.value = [...arr.value, newItem]

替换数组引用在所有设置下都能可靠触发响应式。

常见诱因(按出现频率排序):

  • 对非响应式数组做变更,Vue 无从感知
  • 某些设置下按下标赋值绕过响应式追踪
  • 数组被解构为普通变量,失去响应式

根因

Vue 3 通过 Proxy 追踪响应式数组,其经过包装的数组方法(push、splice 等)会通知依赖方。绕过这些机制的变更——如对普通数组下标赋值、把数组复制到非响应式绑定——不会通知渲染器。

修复

把数组置于 ref/reactive 内,使用 Vue 感知的方法,疑惑时整体替换数组(arr.value = […arr.value, x]),派生视图用 toRefs 或 computed。

注意:深度侦听大数组开销大;应优先用 computed 或按键更新,而非 deep:true 的 watch。

<script setup>
import { ref } from 'vue';
const items = ref([]);

function add(item) {
  items.value.push(item);          // instrumented, reactive
}
function updateFirst(value) {
  items.value = [value, ...items.value.slice(1)]; // replace to be safe
}
</script>

<template>
  <ul><li v-for="i in items" :key="i.id">{{ i.name }}</li></ul>
</template>

验证

通过响应式路径修改数组并确认 UI 更新;断言渲染列表长度与数组长度一致。

修复后补充一条回归测试,复现原始症状,防止问题再次出现。

这类故障通常是环境问题而非纯逻辑错误,因此在缺陷记录中应写明完整命令、环境变量与工作目录。请用最小的脚本复现,待最小用例清楚后再扩大范围。为这类故障准备一份简短的排查清单,能显著减少下次排障时间。