¿Son reactivos los métodos en Vue?

9

He estado usando Vue durante un tiempo, y mi experiencia siempre ha sido un método que volverá a calcular si se actualizan sus datos reactivos subyacentes. He encontrado información contradictoria sobre SO:

  • Intentaba responder a esta pregunta , y me dijeron varias veces que este no era el caso.
  • La respuesta aceptada aquí indica que "[un método] solo se evaluará cuando lo llame explícitamente".

Busqué en los documentos y no vi nada increíblemente claro.

Si no son reactivos, ¿por qué funciona este ejemplo?

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

Realmente me gustaría tener una respuesta definitiva y satisfactoria a la que esta comunidad pueda referirse.

David Weldon
fuente
Gran pregunta: ¡no estoy seguro de que haya una respuesta "oficial" que represente la realidad!
Tyler

Respuestas:

4

Según cómo se rastrean los cambios desde los documentos, esto es lo que está sucediendo:

Vue diagrama de ciclo de reactividad

  1. Se crea un observador especial para la instancia del componente para determinar cuándo se requiere una nueva representación.

  2. Vue convierte todas las propiedades de datagetters y 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. La plantilla se representa. Durante el procesamiento, se realiza una llamada a isAwesomela plantilla.
  2. En el cuerpo de isAwesome, awesomeAnimalIdsse invoca al captador para .
  3. El observador establece una dependencia en el awesomeAnimalIdscampo de data.
  4. Después de un tiempo de espera, awesomeAnimalIdsse actualiza, lo que invoca al awesomeAnimalIdsconfigurador.
  5. Debido a que la plantilla depende de un datacampo que recibió una notificación, se activa una nueva representación.
  6. Repita el paso (3).

A partir de este y este ejemplo anterior, podemos concluir lo siguiente:

Una llamada al método realizada desde una plantilla establece una dependencia reactiva en el subconjunto de datacampos utilizados en la pila de llamadas al método. Si se actualizan los campos subyacentes, se activará una nueva representación del componente.

Existe una idea errónea común de que los métodos se "invocan solo una vez" o "dispara y olvida" cuando se llama desde una plantilla. Claramente, este no es siempre el caso porque los métodos pueden establecer una dependencia reactiva .

Entonces, ¿cuándo debemos usar una propiedad calculada frente a un método?

Consulte la sección de la guía sobre el almacenamiento en caché calculado frente a los métodos . Aquí está mi opinión al respecto:

  • Una propiedad calculada solo se reevaluará cuando sus dependencias reactivas hayan cambiado. Es decir, utiliza el almacenamiento en caché para mejorar la eficiencia.
  • Las propiedades calculadas deben estar libres de efectos secundarios. Por ejemplo, no deberías llamar fetchdesde ellos.
  • Siempre prefiera una propiedad calculada a un método si es posible por razones de eficiencia.
  • Use un método si tiene efectos secundarios o si necesita pasar un argumento (como se ve en la pregunta original).
David Weldon
fuente
Buena explicación clara, gracias.
Ackroydd
4

No, los métodos no son reactivos. Solo los datos pueden ser reactivos en Vue.

PERO es importante entender cómo funciona Vue ...

  1. Vue tomará su plantilla, la compilará en la función de representación y ejecutará la función de representación
  2. Mientras se ejecuta la función de renderizado, Vue monitorea a todos los data()miembros (lo hace todo el tiempo, no solo durante el primer renderizado). Si se accede a alguno de los datos durante el procesamiento, Vue sabe que el contenido de este miembro de datos influye en el resultado del procesamiento.
  3. Vue utilizar el conocimiento reunido en el paso 2. Siempre que el miembro de datos "tocó" durante los cambios de representación, sabe que la repetición debe suceder y hacer lo mismo ...

No importa si hace referencia al miembro de datos directamente, úselo en computedo en un method. Si los datos se "tocan" durante la representación, el cambio de los datos desencadenará una nueva representación en el futuro ...

Michal Levý
fuente
1

Este es un caso muy interesante.

De lo que he leído y de mi experiencia puedo decir que: No, los métodos no son inherentemente reactivos. Se debe llamar explícitamente a un método para que se ejecute.

Pero, ¿cómo puedo explicar su caso? Puse su código en una caja de arena y, efectivamente, a medida que inserta los identificadores en la matriz, la plantilla se actualiza para mostrar el nombre del animal. Esto indicaría cierta reactividad. ¿Lo que da?

Bueno, hice un experimento. Agregué un simple diva cada ciclo que genera un número aleatorio cuando se genera.

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

Y lo que vi fue que cada vez que se introducía una nueva identificación en la matriz, todos los números aleatorios cambiaban. Esta es la clave para entender por qué "parece" que el método isAwesomees reactivo.

De alguna manera, cuando se empuja una nueva ID a la matriz, Vue vuelve a representar el bucle por completo y, por lo tanto, ejecuta los métodos nuevamente. No puedo explicar el funcionamiento interno de por qué vue vuelve a representar todo el ciclo, eso requeriría más investigación.

Entonces para responder a tu pregunta. isAwesomeno es reactivo, es simplemente una ilusión creada por la reproducción del bucle.

T. Short
fuente
1
Es cierto para cualquier propiedad observable en un componente (prop / data / computed). cada vez que se cambian, se dispara, lo updateque causa re-render
ay