未从类实例内部触发 Vue 3 反应性
Posted
技术标签:
【中文标题】未从类实例内部触发 Vue 3 反应性【英文标题】:Vue 3 reactivity not triggered from inside a class instance 【发布时间】:2021-08-25 21:18:12 【问题描述】:Codepen:https://codepen.io/codingkiwi_/pen/XWMBRpW
假设你有一堂课:
class MyClass
constructor()
this.entries = ["a"];
//=== example change triggered from INSIDE the class ===
setTimeout(() =>
this.entries.push("c");
, 1000);
在一个组件中你会得到该类的一个实例:
const reactive = Vue;
const App =
setup()
const myobject = reactive(new MyClass());
//=== example change triggered from OUTSIDE the class ===
setTimeout(() =>
myobject.entries.push("b");
, 500);
return
myobject
;
DOM 中的 myobject.entries 数组将显示条目 "a"
和 "b"
,但不显示 "c"
【问题讨论】:
【参考方案1】:正如另一个答案所解释的,reactive
创建代理对象以启用反应性。构造函数中的this
指的是原始MyClass
实例而不是代理,因此它不能是反应式的。
这表示代码中的探针。 reactive
考虑了MyClass
构造函数中发生的同步操作。在构造函数中执行异步副作用是一种反模式,原因包括可能对使用此类构造函数的代码产生影响。
这可以通过以下方式解决:
class MyClass
constructor()
// synchronous stuff only
this.entries = ["a"];
init()
// asynchronous stuff, probably return a promise
setTimeout(() =>
this.entries.push("c");
, 1000);
和
const myobject = reactive(new MyClass());
myobject.init() // `this` is a proxy inside `init`
【讨论】:
谢谢!构造函数中的反模式实际上只是在示例中:) 在实际代码中,我遇到了这个问题,我在构造函数this.listener = () => this.entities.push();
中定义了一个侦听器函数(以便以后能够取消订阅),所以,就像你解释的那样,“这个" 在监听函数中引用原始实例
在这种情况下,解决方法是不使用箭头方法和惰性绑定方法,例如listener
是常规方法,用作event => this.listener(event)
或this.listener.bind(this)
。 IIRC 这是github.com/NoHomey/bind-decorator 装饰器可以做的事情,以防您的设置支持它们。正如另一篇文章所建议的那样,该类不一定要在 Vue 组件中使用硬编码的 reactive
,但需要在设计时考虑到这一点。【参考方案2】:
DOM 中的 myobject.entries 数组将显示条目
"a"
和"b"
,但不显示"c"
这是因为 "a"
已经在数组中,因为我们使实例具有响应性,并且 "b"
的推送是从对象外部通过代理发生的。
明确:const myobject
不包含MyClass
实例,它包含处理/包装原始实例的实例的Proxy
!它是传递给 DOM / 模板的代理。
"c"
的推送发生在对象内部,不是通过代理。所以"c"
会被推送到数组中,但是不会触发reactivity变化。
修复:
将我们从类内部更改的数组显式标记为reactive
,如下所示:
class MyClass
constructor()
this.entries = reactive(["a"]);
//=== example change triggered from INSIDE the class ===
setTimeout(() =>
this.entries.push("c");
, 1000);
或者尝试只使用文档建议的代理对象:
这里的最佳做法是永远不要持有对原始原始对象的引用,而只使用响应式版本:
文档:https://v3.vuejs.org/guide/reactivity.html#proxy-vs-original-identity
【讨论】:
以上是关于未从类实例内部触发 Vue 3 反应性的主要内容,如果未能解决你的问题,请参考以下文章