Vue 3 反应性未从类实例内部触发

Cod*_*iwi 12 javascript vue.js vue-reactivity vuejs3 vue-composition-api

代码笔: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);
  }
}
Run Code Online (Sandbox Code Playgroud)

在组件中,您可以获得该类的一个实例:

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
    };
  }
}
Run Code Online (Sandbox Code Playgroud)

DOM 中的 myobject.entries 数组将显示条目"a""b",但不显示"c"

Est*_*ask 9

正如另一个答案所解释的,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);
  }
}
Run Code Online (Sandbox Code Playgroud)

const myobject = reactive(new MyClass());
myobject.init() // `this` is a proxy inside `init`
Run Code Online (Sandbox Code Playgroud)


Cod*_*iwi 4

DOM 中的 myobject.entries 数组将显示条目"a""b",但不显示"c"

这是因为"a"当我们使实例具有反应性时, 已经在数组中,并且"b"通过代理从对象外部进行推送。

需要明确的是const myobject不包含MyClass实例,它包含一个Proxy处理/包装原始实例的实例!它是传递给 DOM/模板的代理。

推送是"c"从对象内部发生的,而不是通过代理。所以"c"将被推送到数组,但不会触发任何反应性更改。

使固定:

显式标记我们从类内部更改的数组,如下所示reactive

class MyClass {
  constructor(){
    this.entries = reactive(["a"]);

    //=== example change triggered from INSIDE the class ===
    setTimeout(() => {
      this.entries.push("c");
    }, 1000);
  }
}
Run Code Online (Sandbox Code Playgroud)

或者尝试仅使用代理对象,如文档建议的那样:

这里的最佳实践是永远不要保留对原始原始对象的引用,而只使用反应版本:

文档:https://v3.vuejs.org/guide/reactivity.html#proxy-vs-original-identity