Skip to content

Vue 响应式失效 ​

问题现象 ​

接口返回了新值,但页面仍显示旧值;控制台变量变化与 DOM 更新不一致。先确认组件渲染读取的是否就是被修改的状态。

适用环境 ​

Vue 3,Composition API;示例采用普通 reactive 对象,不涉及 Pinia store 解构。

本文是可复用的排障示例,不代表某次个人生产事故。命令中的名称、账号和数据均为示例,执行前请替换为已确认的目标。

复现或诊断步骤 ​

  1. 用 Vue Devtools 查看组件状态,在点击前后记录同一字段。
  2. 搜索 reactive 对象的解构、重新赋值以及对原始对象的写入。
  3. 在最小组件中保留一个数字字段和按钮;若最小示例正常,逐步恢复业务转换函数。

原因分析 ​

从 reactive 对象解构基本类型会得到当时的值,后续赋值不再经过代理。把局部变量改为另一个 reactive 对象,也不会让原有消费者自动订阅新对象。DOM 异步刷新则属于另一类情况,可在 nextTick 后读取。

修复示例 ​

ts
import { reactive, toRefs, nextTick } from 'vue'
const state = reactive({ count: 0, name: '' })
const { count } = toRefs(state)
async function update() {
  count.value++
  await nextTick()
  // 此处再测量依赖 count 的 DOM
}
function apply(data: { count: number; name: string }) {
  Object.assign(state, data)
}

需要整体替换的数据可使用 ref,并给 .value 赋新对象。需要保留对象身份时更新其属性;Object.assign 不会自动删除旧字段,重置表单时应明确列出字段或使用默认值合并。

验证方法 ​

连续修改字段、重置和异步回填,确认 Devtools 与页面一致。增加 nextTick 只用于判断刷新时机;去掉它后常规文本渲染也应正常。

常见误区 ​

不要用强制刷新页面掩盖引用断开;不要把 Vue 2 的数组索引限制直接套到 Vue 3。对原始对象的写入与对代理的写入也不能混为一谈。

官方参考链接 ​

相关分类:前端 Web · 全部笔记