Skip to content

响应式陷阱

解构失败

js
const user = reactive({ name: 'Alice' })
let name = user
name = 'Bob' // ❌ 页面不会更新

解决方案:

js
const user = reactive({ name: 'Alice' })
user.name = 'Bob' // ✅ 页面会更新
js
const user = reactive({ name: 'Alice' })
let { name } = toRefs(user)
name.value = 'Bob' // ✅ 页面会更新

新增属性是否响应?

  • ✅ Vue3 中新增属性是响应式的
  • ❌ Vue2 中新增属性不是响应式的
js
const user = ref({ name: 'Alice' })
user.value.age = 18 // ✅ 页面会更新
js
const user = reactive({ name: 'Alice' })
user.age = 18 // ✅ 页面会更新
js
export default {
  data() {
    return { user: { name: 'Alice' } }
  },
  mounteds: {
    changeUser() {
      this.user.age = 18 // ❌ Vue2 中页面不会更新
    },
  },
}

Vue2 中的解决方案

js
export default {
  data() {
    return { user: { name: 'Alice' } }
  },
  mounteds: {
    changeUser() {
      this.$set(this.user, 'age', 18) // ✅ 页面会更新
    },
  },
}

数组索引赋值?

  • ✅ Vue3 中数组索引赋值是响应式的
  • ❌ Vue2 中数组索引赋值不是响应式的
js
const list = ref(['A', 'B', 'C'])
list.value[1] = 'X' // ✅ 页面会更新
js
const list = reactive(['A', 'B', 'C'])
list[1] = 'X' // ✅ 页面会更新
js
export default {
  data() {
    return { list: ['A', 'B', 'C'] }
  },
  mounteds: {
    changeList() {
      this.list[1] = 'X' // ❌ 页面不会更新
    },
  },
}

Vue2 中的解决方案

js
export default {
  data() {
    return { list: ['A', 'B', 'C'] }
  },
  mounteds: {
    changeList() {
      this.list.splice(1, 1, 'D') // ✅ 页面会更新
    },
  },
}
js
export default {
  data() {
    return { list: ['A', 'B', 'C'] }
  },
  mounteds: {
    changeList() {
      this.$set(this.list, 1, 'D') // ✅ 页面会更新
    },
  },
}

ref 对象的整体替换

问题说明:在下述的例子中,代码逻辑虽然不会失效,但是会触发 Vue 重新追踪响应式依赖。如果其他地方引用了旧的 state.value,就会“断连”。

js
const state = ref({ count: 0 })

state.value = {
  ...state.value,
  count: state.value.count + 1,
}

推荐写法

js
const state = ref({ count: 0 })

// ✅ 更新单个值
state.value.count++

// ✅ 更新多个值
Object.assign(state.value, {
  count: state.value.count + 1,
  // ...otherProps
})

基于 MIT 许可发布