Czy metody w Vue są reaktywne?

9

Używam Vue od jakiegoś czasu i moje doświadczenie zawsze było metodą, która ponownie obliczy, jeśli podstawowe dane reaktywne zostaną zaktualizowane. Napotkałem sprzeczne informacje na temat SO:

  • Próbowałem odpowiedzieć na to pytanie i wielokrotnie mówiono mi, że tak nie jest.
  • Przyjęta tutaj odpowiedź wskazuje, że „[metoda] zostanie oceniona tylko wtedy, gdy ją wyraźnie wywołasz”.

Przeszukałem dokumenty i nie zauważyłem niczego niesamowicie wyraźnego.

Jeśli nie są reaktywne, to dlaczego ten przykład dział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);
    },
  },
};

I byłoby naprawdę lubią mieć ostateczne i wyczerpującą odpowiedź, że społeczność ta może dotyczyć.

David Weldon
źródło
Świetne pytanie - nie jestem pewien, czy istnieje „oficjalna” odpowiedź, która reprezentuje rzeczywistość!
Tyler

Odpowiedzi:

4

Na podstawie tego, jak śledzone są zmiany z dokumentów, oto, co się dzieje:

Schemat cyklu reaktywności Vue

  1. Dla instancji komponentu tworzony jest specjalny obserwator, który określa, kiedy wymagane jest ponowne renderowanie.

  2. Vue konwertuje wszystkie właściwości datana getters i 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. Szablon jest renderowany. Podczas renderowania isAwesomez szablonu jest wywoływane polecenie
  2. W treści wywoływany jest isAwesomegetter for awesomeAnimalIds.
  3. Obserwator ustala zależność od awesomeAnimalIdspola data.
  4. Po upływie limitu czasu awesomeAnimalIdsjest aktualizowany, co wywołuje awesomeAnimalIdssetera.
  5. Ponieważ szablon zależy od datapola, które otrzymało powiadomienie, uruchamiane jest ponowne renderowanie.
  6. Powtórz krok (3).

Na podstawie powyższego i powyższego przykładu możemy wyciągnąć następujące wnioski:

Wywołanie metody wykonane z szablonu ustanawia reaktywną zależność od podzbioru datapól używanych w stosie wywołań metody. Jeśli podstawowe pola zostaną zaktualizowane, spowoduje to ponowne renderowanie komponentu.

Istnieje powszechne nieporozumienie, że metody są „wywoływane tylko raz” lub „odpalają i zapominają”, gdy są wywoływane z szablonu. Oczywiście nie zawsze tak jest, ponieważ metody mogą ustalić zależność reaktywną .

Kiedy więc powinniśmy użyć obliczonej właściwości vs metody?

Zobacz sekcję przewodnika dotyczącą buforowania obliczeniowego a metod . Oto moje zdanie na ten temat:

  • Obliczona właściwość zostanie ponownie oszacowana tylko wtedy, gdy zmienią się jej zależności reaktywne. Oznacza to, że wykorzystuje buforowanie w celu zwiększenia wydajności.
  • Obliczone właściwości powinny być wolne od skutków ubocznych. Np. Nie powinieneś dzwonić fetchod nich.
  • Zawsze preferuj obliczoną właściwość od metody, jeśli to możliwe ze względu na wydajność.
  • Użyj metody, jeśli masz skutki uboczne lub musisz podać argument (jak widać w pierwotnym pytaniu).
David Weldon
źródło
Ładne, jasne wyjaśnienie, dzięki.
Ackroydd
4

Nie, metody nie są reaktywne. Tylko dane mogą być reaktywne w Vue.

ALE ważne jest, aby zrozumieć, jak działa Vue ...

  1. Vue weźmie szablon, skompiluje go w funkcję renderowania i uruchomi funkcję renderowania
  2. Gdy funkcja renderowania jest uruchomiona, Vue monitoruje wszystkich data()członków (robi to cały czas, nie tylko podczas pierwszego renderowania). Jeśli jakiekolwiek dane są dostępne podczas renderowania, Vue wie, że zawartość tego elementu danych wpływa na wynik renderowania.
  3. Vue korzysta z wiedzy zebranej w kroku 2. Ilekroć członek danych „dotknął” podczas renderowania zmian, wie, że ponowne renderowanie powinno nastąpić i zrobić to ...

Nie ma znaczenia, czy odwołujesz się bezpośrednio do członka danych, używasz go w computedlub w method. Jeśli dane zostaną „dotknięte” podczas renderowania, zmiana danych spowoduje ponowne renderowanie w przyszłości ...

Michal Levý
źródło
1

To bardzo interesujący przypadek.

Z tego, co przeczytałem i z mojego doświadczenia mogę powiedzieć, że: Nie, metody nie są z natury reaktywne. Metoda musi zostać jawnie wywołana, aby mogła zostać wykonana.

Ale jak mogę wyjaśnić twoją sprawę? Umieściłem twój kod w piaskownicy i na pewno, kiedy wpychasz id do tablicy, szablon aktualizuje się, aby wyświetlić nazwę zwierzęcia. Oznaczałoby to pewną reaktywność. Co daje?

Cóż, przeprowadziłem eksperyment. Dodałem prostą divdo każdej pętli, która generuje losową liczbę po wygenerowaniu.

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

I zobaczyłem, że za każdym razem, gdy nowy identyfikator jest wpychany do tablicy, wszystkie losowe liczby będą się zmieniać. Jest to klucz do zrozumienia, dlaczego „wydaje się”, jakby metoda isAwesomebyła reaktywna.

W jakiś sposób, gdy nowy identyfikator jest wypychany do tablicy, Vue ponownie renderuje pętlę całkowicie, tym samym ponownie wykonując metody. Nie potrafię wyjaśnić, dlaczego Vue ponownie przetwarza całą pętlę, co wymagałoby dalszych badań.

Aby odpowiedzieć na twoje pytanie. isAwesomenie jest reaktywny, jest jedynie iluzją stworzoną przez ponowne renderowanie pętli.

T. Krótki
źródło
1
dotyczy to każdej obserwowalnej właściwości komponentu (prop / data / computing). za każdym razem, gdy są zmieniane, wyzwala to, updateco powoduje a re-renderi uruchamia wszelkie metody powiązane w szablonie
Ohgodwhy