I metodi in Vue sono reattivi?


9

Sto usando Vue da un po 'e la mia esperienza è sempre stata un metodo che verrà ricalcolato se i suoi dati reattivi sottostanti vengono aggiornati. Ho riscontrato informazioni contrastanti su SO:

  • Stavo tentando di rispondere a questa domanda e mi è stato detto più volte che non è così.
  • La risposta accettata qui indica che "[un metodo] saranno valutate solo quando si chiama in modo esplicito."

Ho cercato tra i documenti e non ho visto nulla di incredibilmente chiaro.

Se non sono reattivi, perché funziona questo esempio?

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

Mi piacerebbe davvero avere una risposta definitiva e soddisfacente a cui questa comunità possa fare riferimento.


Grande domanda - non sono sicuro che esista una risposta "ufficiale" che rappresenti la realtà!
Tyler

Risposte:


4

In base a come vengono monitorate le modifiche dai documenti, ecco cosa sta succedendo:

Diagramma del ciclo di reattività Vue

  1. Viene creato un watcher speciale per l'istanza del componente per determinare quando è necessario un nuovo rendering.

  2. Vue converte tutte le proprietà di datain getter e 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. Il modello è reso. Durante il rendering, isAwesomeviene effettuata una chiamata a dal modello.
  2. Nel corpo di isAwesome, awesomeAnimalIdsviene invocato il getter per .
  3. L'osservatore stabilisce una dipendenza dal awesomeAnimalIdscampo di data.
  4. Dopo un timeout, awesomeAnimalIdsviene aggiornato, che richiama il awesomeAnimalIdssetter.
  5. Poiché il modello dipende da un datacampo che ha ricevuto una notifica, viene attivato un nuovo rendering.
  6. Ripetere il passaggio (3).

Da questo e questo esempio sopra, possiamo concludere quanto segue:

Una chiamata di metodo effettuata da un modello stabilisce una dipendenza reattiva dal sottoinsieme di datacampi utilizzati nello stack di chiamate del metodo. Se i campi sottostanti vengono aggiornati, verrà attivato un nuovo rendering del componente.

C'è un malinteso comune sul fatto che i metodi siano "invocati solo una volta" o "spara e dimentica" quando chiamati da un modello. Questo chiaramente non è sempre il caso perché i metodi possono stabilire una dipendenza reattiva .

Quindi, quando dovremmo usare una proprietà calcolata rispetto a un metodo?

Consulta la sezione guida su Cache calcolata e metodi . Ecco la mia opinione su di esso:

  • Una proprietà calcolata verrà rivalutata solo quando le sue dipendenze reattive sono cambiate. Cioè utilizza la memorizzazione nella cache per una maggiore efficienza.
  • Le proprietà calcolate dovrebbero essere prive di effetti collaterali. Ad esempio, non dovresti chiamare fetchda loro.
  • Preferisci sempre una proprietà calcolata a un metodo, se possibile, per motivi di efficienza.
  • Utilizzare un metodo se si hanno effetti collaterali o se è necessario passare un argomento (come si vede nella domanda originale).

Bella spiegazione chiara, grazie.
Ackroydd,

4

No, i metodi non sono reattivi. Solo i dati possono essere reattivi in ​​Vue.

MA è importante capire come funziona Vue ...

  1. Vue prenderà il tuo modello, lo compila nella funzione di rendering ed esegue la funzione di rendering
  2. Mentre la funzione di rendering è in esecuzione, Vue monitora tutti i data()membri (lo fa sempre, non solo durante il primo rendering). Se si accede a uno dei dati durante il rendering, Vue sa che il contenuto di questo membro di dati influenza il risultato del rendering.
  3. Vue utilizza le conoscenze raccolte nel passaggio 2. Ogni volta che un membro dei dati "si tocca" durante il rendering delle modifiche, sa che il rendering deve avvenire e fare le cose ...

Non importa se si fa riferimento direttamente al membro dei dati, lo si utilizza in computedo in a method. Se i dati vengono "toccati" durante il rendering, la modifica dei dati attiverà il rendering in futuro ...


1

Questo è un caso molto interessante.

Da quello che ho letto e dalla mia esperienza posso dire che: No, i metodi non sono intrinsecamente reattivi. Un metodo deve essere esplicitamente chiamato per l'esecuzione.

Ma allora come posso spiegare il tuo caso? Ho inserito il tuo codice in una sandbox e sicuramente, mentre spingi gli ID nell'array, il modello si aggiorna per visualizzare il nome dell'animale. Ciò indicherebbe una certa reattività. Cosa dà?

Bene, ho fatto un esperimento. Ho aggiunto un semplice divad ogni loop che genera un numero casuale quando generato.

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

E quello che ho visto è che ogni volta che un nuovo ID veniva inserito nell'array, tutti i numeri casuali sarebbero cambiati. Questa è la chiave per capire perché "sembra" come se il metodo isAwesomefosse reattivo.

In qualche modo, quando un nuovo ID viene inviato all'array, Vue esegue nuovamente il rendering del ciclo completamente, quindi eseguendo nuovamente i metodi. Non riesco a spiegare il funzionamento interno del perché Vue ricalchi l'intero ciclo, il che richiederebbe ulteriori ricerche.

Quindi per rispondere alla tua domanda. isAwesomenon è reattivo, è semplicemente un'illusione creata dal rendering del loop.


1
è vero per qualsiasi proprietà osservabile in un componente (prop / dati / calcolati). ogni volta che vengono cambiate si innesca il updateche provoca a re-rendere innesca tutti i metodi associati al modello
Ohgodwhy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.