Vue中的方法具有反应性吗?


9

我使用Vue已有一段时间了,我的经验一直是,如果更新了其基础反应性数据,该方法将重新计算。我在SO上遇到了冲突的信息:

  • 我试图回答这个问题,并多次被告知并非如此。
  • 此处接受的答案表示“ [a方法]仅在您显式调用它时才会被评估。”

我搜索了文档,但没有发现任何令人难以置信的清晰之处。

如果它们没有反应性,那么为什么这个示例起作用?

<ul>
  <li v-for="animal in animals" :key="animal.id">
    <span v-if="isAwesome(animal)">{{ animal.name }}</span>
  </li>
</ul>
export default {
  data() {
    return {
      awesomeAnimalIds: [],
      animals: [
        { id: 1, name: 'dog' },
        { id: 5, name: 'cat' },
        { id: 9, name: 'fish' },
      ],
    };
  },
  created() {
    setTimeout(() => {
      this.awesomeAnimalIds.push(5);
    }, 1000);
    setTimeout(() => {
      this.awesomeAnimalIds.push(9);
    }, 2000);
  },
  methods: {
    isAwesome(animal) {
      return this.awesomeAnimalIds.includes(animal.id);
    },
  },
};

真的很想得到这个社区可以参考的明确而令人满意的答案。


好问题-不确定是否有代表现实的“官方”答案!
泰勒

Answers:


4

根据文档中如何跟踪更改,以下是发生的情况:

Vue反应周期图

  1. 为组件实例创建一个特殊的观察器,以确定何时需要重新渲染。

  2. Vue将of的所有属性转换data为getter和setter。

get animals() {
  // Add dependency: potentially trigger a re-render if animals updates
  ...
}
set animals() {
  // Notify the watcher that animals has been updated
  ...
}
get awesomeAnimalIds() {
  // Add dependency: potentially trigger a re-render if awesomeAnimalIds updates
  ...
}
set awesomeAnimalIds() {
  // Notify the watcher that awesomeAnimalIds has been updated
  ...
}

  1. 模板被渲染。在渲染期间,isAwesome会从模板进行调用。
  2. 在中isAwesomeawesomeAnimalIds调用的getter 。
  3. 观察者建立对awesomeAnimalIds字段的依赖data
  4. 超时后,awesomeAnimalIds将进行更新,这将调用awesomeAnimalIds设置器。
  5. 由于模板取决于data接收到通知的字段,因此将触发重新渲染。
  6. 重复步骤(3)。

从上面的这个例子中,我们可以得出以下结论:

从模板进行的方法调用建立了data对方法调用堆栈中使用的字段子集的反应性依赖性。如果基础字段被更新,它将触发组件的重新渲染。

有一个常见的误解,即从模板调用方法时,方法“仅调用一次”或“即发即弃”。显然并非总是如此,因为方法可以建立反应性依赖性

那么什么时候应该使用计算属性还是方法呢?

请参阅有关“ 计算缓存与方法”的指南部分。这是我的看法:

  • 计算属性仅在其反应相关性已更改时才会重新评估。即,它使用缓存来提高效率。
  • 计算的属性应无副作用。例如,您不应该打给fetch他们。
  • 出于效率考虑,如果可能的话,总是要优先选择计算属性而不是方法。
  • 如果您有副作用或需要传递参数(如原始问题所示),请使用一种方法。

好的清楚的解释,谢谢。
阿克罗伊德

4

不,方法不是被动的。Vue中只有数据可以是反应性的。

但是了解Vue的工作原理很重要...

  1. Vue将使用您的模板,将其编译为渲染函数并运行渲染函数
  2. 在渲染功能运行时,Vue监视所有data()成员(它一直在执行此操作,不仅在第一次渲染期间执行)。如果在渲染期间访问了任何数据,则Vue知道该数据成员的内容会影响渲染结果。
  3. Vue使用在步骤2中收集的知识。只要在渲染更改期间“触摸”数据成员,它就会知道应该进行重新渲染并执行该操作。

直接引用数据成员,在computed或中使用它都没关系method如果在渲染过程中“触摸”数据,则数据的更改将在将来触发重新渲染...


1

这是一个非常有趣的案例。

根据我的阅读和经验,我可以说:不,方法并不是天生的反应。必须显式调用方法才能执行。

但是,那我该如何解释您的情况呢?我将您的代码放在沙箱中,当您将ID推入数组时,可以肯定地,模板会更新以显示动物名称。这表明有些反应性。是什么赋予了?

好吧,我做了一个实验。我div为每个循环添加了一个简单的变量,该变量在生成时会生成一个随机数。

<li v-for="animal in animals" :key="animal.id">
        <div>{{ random() }}</div>
        <span v-if="isAwesome(animal)">{{ animal.name }}</span>
</li>

...

random() {
      return Math.random();
}

我看到的是,每次将新的id推入数组时,所有随机数都会改变。这是理解为什么该方法似乎isAwesome是反应性的“似乎”的关键。

不知何故,当将新的ID推送到数组时,Vue会完全重新渲染循环,从而再次执行方法。我无法解释vue为什么重新呈现整个循环的内部工作原理,这需要进一步的研究。

因此,回答您的问题。isAwesome它不是被动的,只是循环的重新渲染而产生的一种幻觉。


1
对于组件中的任何可观察属性(属性/数据/计算属性)都是如此。每当更改它们时,它就会触发update并导致re-render并触发模板中绑定的任何方法
Ohgodwhy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.