Les méthodes de Vue sont-elles réactives?


9

J'utilise Vue depuis un certain temps, et mon expérience a toujours été une méthode qui recalculera si ses données réactives sous-jacentes sont mises à jour. J'ai rencontré des informations contradictoires sur SO:

  • J'essayais de répondre à cette question et on m'a dit à plusieurs reprises que ce n'était pas le cas.
  • La réponse acceptée ici indique que "[une méthode] ne sera évaluée que si vous l'appelez explicitement."

J'ai cherché dans les documents et je n'ai rien vu d'incroyablement clair.

S'ils ne sont pas réactifs, pourquoi cet exemple fonctionne-t-il?

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

J'aimerais vraiment avoir une réponse définitive et satisfaisante à laquelle cette communauté puisse se référer.


Grande question - pas sûr qu'il y ait une réponse "officielle" qui représente la réalité!
Tyler

Réponses:


4

En fonction de la façon dont les modifications sont suivies à partir des documents, voici ce qui se passe:

Diagramme du cycle de réactivité Vue

  1. Un observateur spécial est créé pour l'instance de composant afin de déterminer quand un nouveau rendu est requis.

  2. Vue convertit toutes les propriétés de dataen getters et setters.

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. Le modèle est rendu. Pendant le rendu, un appel à isAwesomeest effectué à partir du modèle.
  2. Dans le corps de isAwesome, le getter for awesomeAnimalIdsest invoqué.
  3. L'observateur établit une dépendance sur le awesomeAnimalIdsdomaine de data.
  4. Après un timeout, awesomeAnimalIdsest mis à jour, ce qui appelle le awesomeAnimalIdssetter.
  5. Étant donné que le modèle dépend d'un datachamp qui a reçu une notification, un nouveau rendu est déclenché.
  6. Répétez l'étape (3).

De ceci et de cet exemple ci-dessus, nous pouvons conclure ce qui suit:

Un appel de méthode effectué à partir d'un modèle établit une dépendance réactive avec le sous-ensemble de datachamps utilisé dans la pile d'appels de méthode. Si les champs sous-jacents sont mis à jour, cela déclenchera un nouveau rendu du composant.

Il existe une idée fausse courante selon laquelle les méthodes ne sont "invoquées qu'une seule fois" ou "tirent et oublient" lorsqu'elles sont appelées à partir d'un modèle. Ce n'est clairement pas toujours le cas car les méthodes peuvent établir une dépendance réactive .

Alors, quand devrions-nous utiliser une propriété calculée par rapport à une méthode?

Consultez la section du guide sur la mise en cache calculée et les méthodes . Voici mon point de vue:

  • Une propriété calculée ne sera réévaluée que lorsque ses dépendances réactives auront changé. C'est à dire qu'il utilise la mise en cache pour une efficacité améliorée.
  • Les propriétés calculées doivent être exemptes d'effets secondaires. Par exemple, vous ne devriez pas appeler fetchd'eux.
  • Préférez toujours une propriété calculée à une méthode si possible pour des raisons d'efficacité.
  • Utilisez une méthode si vous avez des effets secondaires ou si vous devez passer un argument (comme vu dans la question d'origine).

Belle explication claire, merci.
Ackroydd

4

Non, les méthodes ne sont pas réactives. Seules les données peuvent être réactives dans Vue.

MAIS c'est important de comprendre comment fonctionne Vue ...

  1. Vue prendra votre modèle, le compilera en fonction de rendu et exécutera la fonction de rendu
  2. Pendant que la fonction de rendu est en cours d'exécution, Vue surveille tous les data()membres (il le fait tout le temps, pas seulement pendant le premier rendu). Si l'une des données est accessible pendant le rendu, Vue sait que le contenu de ce membre de données influence le résultat du rendu.
  3. Vue utilise les connaissances recueillies à l'étape 2. Chaque fois que le membre de données "a touché" pendant les modifications de rendu, il sait que le nouveau rendu doit avoir lieu et faire la chose ...

Peu importe si vous référencez directement le membre de données, utilisez-le dans computedou dans un method. Si les données sont "touchées" pendant le rendu, le changement des données déclenchera un nouveau rendu à l'avenir ...


1

C'est un cas très intéressant.

D'après ce que j'ai lu et mon expérience, je peux dire que: Non, les méthodes ne sont pas intrinsèquement réactives. Une méthode doit être explicitement appelée pour qu'elle s'exécute.

Mais alors, comment puis-je expliquer votre cas? J'ai mis votre code dans un bac à sable et bien sûr, lorsque vous poussez les identifiants dans le tableau, le modèle se met à jour pour afficher le nom de l'animal. Cela indiquerait une certaine réactivité. Ce qui donne?

Eh bien, j'ai mené une expérience. J'ai ajouté un simple divà chaque boucle qui génère un nombre aléatoire lors de sa génération.

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

Et ce que j'ai vu, c'est qu'à chaque fois qu'un nouvel identifiant est inséré dans le tableau, tous les nombres aléatoires changent. C'est la clé pour comprendre pourquoi il «semble» que la méthode isAwesomeest réactive.

D'une manière ou d'une autre, lorsqu'un nouvel ID est poussé vers le tableau, Vue restitue entièrement la boucle, exécutant ainsi à nouveau les méthodes. Je ne peux pas expliquer le fonctionnement interne de la raison pour laquelle la vue restitue la boucle entière, ce qui nécessiterait des recherches supplémentaires.

Donc, pour répondre à votre question. isAwesomen'est pas réactif, c'est simplement une illusion créée par le re-rendu de la boucle.


1
c'est vrai pour toute propriété observable dans un composant (prop / data / computed). chaque fois qu'ils sont modifiés, il déclenche updatece qui provoque un re-renderet déclenche toutes les méthodes liées dans le modèle
Ohgodwhy
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.