Sind Methoden in Vue reaktiv?

9

Ich benutze Vue schon eine Weile und meine Erfahrung war immer, dass eine Methode neu berechnet wird, wenn die zugrunde liegenden reaktiven Daten aktualisiert werden. Ich habe widersprüchliche Informationen zu SO gefunden:

  • Ich habe versucht, diese Frage zu beantworten , und mir wurde mehrmals gesagt, dass dies nicht der Fall ist.
  • Die akzeptierte Antwort hier zeigt an, dass „[ein Verfahren] wird nur ausgewertet werden , wenn Sie es explizit nennen.“

Ich habe die Dokumente durchsucht und nichts unglaublich klares gesehen.

Wenn sie nicht reaktiv sind, warum funktioniert dieses Beispiel dann?

<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);
    },
  },
};

Ich hätte wirklich gerne eine endgültige und zufriedenstellende Antwort, auf die sich diese Community beziehen kann.

David Weldon
quelle
Tolle Frage - nicht sicher, ob es eine "offizielle" Antwort gibt, die die Realität darstellt!
Tyler

Antworten:

4

Basierend auf der Art und Weise, wie Änderungen aus den Dokumenten verfolgt werden, ist Folgendes zu tun:

Vue-Reaktivitätszyklusdiagramm

  1. Für die Komponenteninstanz wird ein spezieller Watcher erstellt, um zu bestimmen, wann ein erneutes Rendern erforderlich ist.

  2. Vue konvertiert alle Eigenschaften von datain Getter und 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. Die Vorlage wird gerendert. Während des Renderns wird ein Aufruf anisAwesome wird aus der Vorlage getätigt.
  2. Im Körper von isAwesomewird der Getter für awesomeAnimalIdsaufgerufen.
  3. Der Beobachter stellt eine Abhängigkeit vom awesomeAnimalIdsFeld von herdata .
  4. Nach einer Zeitüberschreitung awesomeAnimalIdswird aktualisiert, wodurch die aufgerufen wirdawesomeAnimalIds Setter aufgerufen wird.
  5. Weil die Vorlage von a abhängt data Feld , das eine Benachrichtigung erhalten hat, wird ein erneutes Rendern ausgelöst.
  6. Wiederholen Sie Schritt (3).

Aus diesem und diesem obigen Beispiel können wir Folgendes schließen:

Ein Methodenaufruf aus einer Vorlage stellt eine reaktive Abhängigkeit von der Teilmenge der dataFelder her, die im Methodenaufrufstapel verwendet werden. Wenn die zugrunde liegenden Felder aktualisiert werden, wird ein erneutes Rendern der Komponente ausgelöst.

Es gibt ein weit verbreitetes Missverständnis, dass Methoden "nur einmal aufgerufen" oder "ausgelöst und vergessen" werden, wenn sie aus einer Vorlage aufgerufen werden. Dies ist eindeutig nicht immer der Fall, da Methoden eine reaktive Abhängigkeit herstellen können .

Wann sollten wir also eine berechnete Eigenschaft gegenüber einer Methode verwenden?

Weitere Informationen finden Sie im Leitfaden zu Computed Caching vs Methods . Hier ist meine Meinung dazu:

  • Eine berechnete Eigenschaft wird nur dann neu bewertet, wenn sich ihre reaktiven Abhängigkeiten geändert haben. Das heißt, es wird Caching verwendet, um die Effizienz zu verbessern.
  • Die berechneten Eigenschaften sollten frei von Nebenwirkungen sein. ZB solltest du nicht fetchvon ihnen anrufen .
  • Ziehen Sie aus Effizienzgründen immer eine berechnete Eigenschaft einer Methode vor, wenn dies möglich ist.
  • Verwenden Sie eine Methode, wenn Sie Nebenwirkungen haben oder wenn Sie ein Argument übergeben müssen (wie in der ursprünglichen Frage gezeigt).
David Weldon
quelle
Schöne klare Erklärung, danke.
Ackroydd
4

Nein, Methoden sind nicht reaktiv. In Vue können nur Daten reaktiv sein.

ABER es ist wichtig zu verstehen, wie Vue funktioniert ...

  1. Vue nimmt Ihre Vorlage, kompiliert sie in die Renderfunktion und führt die Renderfunktion aus
  2. Während die Renderfunktion ausgeführt wird, überwacht Vue alle data() Mitglieder (dies geschieht ständig, nicht nur beim ersten Rendern). Wenn während des Renderns auf Daten zugegriffen wird, weiß Vue, dass der Inhalt dieses Datenelements das Ergebnis des Renderns beeinflusst.
  3. Vue verwendet das in Schritt 2 gesammelte Wissen. Immer wenn ein Datenelement während des Renderns Änderungen "berührt" hat, weiß es, dass ein erneutes Rendern stattfinden und die Sache tun sollte ...

Es spielt keine Rolle, ob Sie das Datenelement direkt referenzieren, es in computedoder in einem verwenden method. Wenn die Daten während des Renderns "berührt" werden, wird die Änderung der Daten in Zukunft ein erneutes Rendern auslösen ...

Michal Levý
quelle
1

Dies ist ein sehr interessanter Fall.

Nach dem, was ich gelesen habe und meiner Erfahrung kann ich sagen: Nein, Methoden sind nicht von Natur aus reaktiv. Eine Methode muss explizit aufgerufen werden, damit sie ausgeführt werden kann.

Aber wie kann ich dann Ihren Fall erklären? Ich habe Ihren Code in eine Sandbox eingegeben und sicher genug, wenn Sie IDs in das Array schieben, wird die Vorlage aktualisiert, um den Tiernamen anzuzeigen. Dies würde auf eine gewisse Reaktivität hinweisen. Was gibt?

Nun, ich habe ein Experiment durchgeführt. Ich divhabe jeder Schleife eine einfache hinzugefügt , die beim Generieren eine Zufallszahl generiert.

<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();
}

Und was ich sah, war, dass sich jedes Mal, wenn eine neue ID in das Array verschoben wurde, alle Zufallszahlen änderten. Dies ist der Schlüssel, um zu verstehen, warum es "scheint", als ob die Methode isAwesomereaktiv ist.

Wenn eine neue ID in das Array verschoben wird, rendert Vue die Schleife irgendwie vollständig neu und führt die Methoden erneut aus. Ich kann das Innenleben nicht erklären, warum Vue die gesamte Schleife neu rendert, was weitere Forschung erfordern würde.

Also, um deine Frage zu beantworten. isAwesomeist nicht reaktiv, es ist lediglich eine Illusion, die durch das erneute Rendern der Schleife erzeugt wird.

T. Short
quelle
1
Dies gilt für jede beobachtbare Eigenschaft in einer Komponente (prop / data / computed). Wenn sie geändert werden, updatewird ein re-renderTrigger
ausgelöst,