Javascript Vue 3不是从类实例内部触发的
代码笔: 假设你有一门课:Javascript Vue 3不是从类实例内部触发的,javascript,vue.js,vuejs3,vue-composition-api,vue-reactivity,Javascript,Vue.js,Vuejs3,Vue Composition Api,Vue Reactivity,代码笔: 假设你有一门课: class-MyClass{ 构造函数(){ this.entries=[“a”]; //==从类内部触发的示例更改=== 设置超时(()=>{ 这个.entries.push(“c”); }, 1000); } } 在组件中,您可以得到该类的一个实例: const{reactive}=Vue; 常量应用={ 设置(){ const myobject=reactive(新的MyClass()); //==从类外部触发的示例更改=== 设置超时(()=>{ myobj
class-MyClass{
构造函数(){
this.entries=[“a”];
//==从类内部触发的示例更改===
设置超时(()=>{
这个.entries.push(“c”);
}, 1000);
}
}
在组件中,您可以得到该类的一个实例:
const{reactive}=Vue;
常量应用={
设置(){
const myobject=reactive(新的MyClass());
//==从类外部触发的示例更改===
设置超时(()=>{
myobject.entries.push(“b”);
}, 500);
返回{
肌体
};
}
}
DOM中的myobject.entries数组将显示条目“a”
和“b”
,但不显示“c”
DOM中的myobject.entries数组将显示条目“a”
和“b”
,但不显示“c”
这是因为“a”
已经在数组中,因为我们使实例处于反应状态,“b”
的推送是从对象外部通过代理进行的
要清楚:const myobject
不包含MyClass
实例,它包含处理/包装原始实例的实例的代理
!它是传递给DOM/模板的代理
“c”
的推送是从对象内部进行的,而不是通过代理进行的。因此,“c”
将被推送到阵列,但不会触发反应性变化
修正:
将我们从类内部更改的数组显式标记为reactive
,如下所示:
class-MyClass{
构造函数(){
this.entries=反应性([“a”]);
//==从类内部触发的示例更改===
设置超时(()=>{
这个.entries.push(“c”);
}, 1000);
}
}
或者,尝试仅使用代理对象,如文档建议的:
这里的最佳实践是永远不要保留对原始对象的引用,而只使用被动版本:
文档:另一个答案解释道,
反应性
创建代理对象以启用反应性构造函数中的此
引用原始的MyClass
实例,而不是代理,因此它不能是被动的
这表示代码中的问题<代码>反应式考虑在MyClass
构造函数中发生的同步操作。在构造函数中执行异步副作用是一种反模式,原因包括使用这种构造函数的代码可能带来的影响
这可以通过以下方法解决:
class MyClass {
constructor(){
// synchronous stuff only
this.entries = ["a"];
}
init() {
// asynchronous stuff, probably return a promise
setTimeout(() => {
this.entries.push("c");
}, 1000);
}
}
及
非常感谢。构造函数中的反模式实际上就在示例中:)在实际代码中,我遇到了这个问题,我在构造函数中定义了一个侦听器函数
this.listener=()=>{this.entities.push();}
(以后可以取消订阅),因此,正如您所解释的,“这”在引用原始实例的侦听器函数中,在这种情况下,解决方法是不使用箭头方法和延迟绑定方法,例如,listener
是常规方法,用作event=>this.listener(event)
或this.listener.bind(this)
。IIRC这是装饰师可以做的事情,以防您的设置支持它们。正如另一篇文章所建议的那样,该类不一定要在Vue组件内部使用硬编码的反应式,但它的设计需要考虑到这一点。
const myobject = reactive(new MyClass());
myobject.init() // `this` is a proxy inside `init`