非响应式属性修改后为何在 Vue.js 中表现得像响应式属性?
2024-03-16 07:59:58
非响应式属性修改为何在 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
不会触发响应式系统,因为它是一个局部变量。
解决方法
可以通过两种方式解决此问题:
-
使用
Vue.set()
: 使用Vue.set()
方法显式地使local_variable
响应式。 -
延迟修改: 在修改
local_variable
之前引入延迟,这将允许响应式系统在将local_variable
赋值给reactiveObject.data
后捕获更改。
结论
修改非响应式属性不会使该属性变为响应式。当将非响应式对象赋值给响应式对象的属性时,该属性的 setter
会被包装,从而在每次修改该属性时触发侦听器。但是,在修改局部非响应式变量时,不会触发侦听器。
常见问题解答
-
为什么在修改局部变量时侦听器没有触发?
因为局部变量本身不是通过 Vue 的响应式系统使其响应式的。 -
使用
Vue.set()
有什么缺点?
使用Vue.set()
会导致性能开销,因为每次修改属性时都必须调用该方法。 -
延迟修改的最佳延迟时间是多少?
最佳延迟时间取决于应用程序。一般来说,使用短延迟(例如 1 毫秒)就足够了。 -
有什么方法可以避免这种问题?
可以遵循以下最佳实践:- 始终使用
Vue.set()
将对象添加到响应式对象中。 - 避免在局部变量上修改响应式对象的属性。
- 始终使用
-
我应该在什么情况下使用
Vue.set()
?- 当动态添加或删除响应式对象的属性时。
- 当将非响应式对象赋值给响应式对象的属性时。