返回

非响应式属性修改后为何在 Vue.js 中表现得像响应式属性?

vue.js

非响应式属性修改为何在 Vue.js 中表现得像响应式属性?

简介

Vue.js 中的响应式系统是一个强大的工具,可以使应用程序对数据的变化做出反应。然而,在某些情况下,非响应式属性的修改似乎反映在响应式系统中,这可能会导致令人惊讶的结果。

问题

在本文中,我们将探讨一个具体问题,即在将非响应式对象赋值给响应式对象的属性后,修改局部非响应式变量会导致响应式侦听器被触发。

代码示例

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

class MyClass {
  data = null;

  assignAndUpdateImmediate() {
    const local_variable = { name: 'Immediate: initial' };
    this.data = local_variable;
    local_variable.name = 'Immediate: updated';
  }
}

const reactiveObject = reactive(new MyClass());

watch(() => reactiveObject.data?.name, (newName, oldName) => {
  console.log(`WATCHER: "${oldName}" -> "${newName}"`);
});

reactiveObject.assignAndUpdateImmediate();
</script>

输出

WATCHER: "undefined" -> "Immediate: updated"

分析

在这种情况下,将 local_variable 赋值给 reactiveObject.data 会触发响应式系统,因为 reactiveObject 是一个响应式对象。然而,修改 local_variable 不会触发响应式系统,因为它是一个局部变量。

解决方法

可以通过两种方式解决此问题:

  1. 使用 Vue.set() 使用 Vue.set() 方法显式地使 local_variable 响应式。

  2. 延迟修改: 在修改 local_variable 之前引入延迟,这将允许响应式系统在将 local_variable 赋值给 reactiveObject.data 后捕获更改。

结论

修改非响应式属性不会使该属性变为响应式。当将非响应式对象赋值给响应式对象的属性时,该属性的 setter 会被包装,从而在每次修改该属性时触发侦听器。但是,在修改局部非响应式变量时,不会触发侦听器。

常见问题解答

  1. 为什么在修改局部变量时侦听器没有触发?
    因为局部变量本身不是通过 Vue 的响应式系统使其响应式的。

  2. 使用 Vue.set() 有什么缺点?
    使用 Vue.set() 会导致性能开销,因为每次修改属性时都必须调用该方法。

  3. 延迟修改的最佳延迟时间是多少?
    最佳延迟时间取决于应用程序。一般来说,使用短延迟(例如 1 毫秒)就足够了。

  4. 有什么方法可以避免这种问题?
    可以遵循以下最佳实践:

    • 始终使用 Vue.set() 将对象添加到响应式对象中。
    • 避免在局部变量上修改响应式对象的属性。
  5. 我应该在什么情况下使用 Vue.set()

    • 当动态添加或删除响应式对象的属性时。
    • 当将非响应式对象赋值给响应式对象的属性时。