Apakah metode dalam Vue reaktif?

9

Saya telah menggunakan Vue untuk sementara waktu, dan pengalaman saya selalu menjadi metode yang akan menghitung ulang jika data reaktif yang mendasarinya diperbarui. Saya mengalami informasi yang saling bertentangan pada SO:

  • Saya mencoba menjawab pertanyaan ini , dan diberi tahu berulang kali bahwa ini bukan masalahnya.
  • Jawaban yang diterima di sini menunjukkan bahwa "[metode] hanya akan dievaluasi ketika Anda secara eksplisit menyebutnya."

Saya mencari di dokumen dan saya tidak melihat sesuatu yang sangat jelas.

Jika mereka tidak reaktif, lalu mengapa contoh ini berfungsi?

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

Saya benar - benar ingin memiliki jawaban yang pasti dan memuaskan yang dapat dirujuk oleh komunitas ini.

David Weldon
sumber
Pertanyaan bagus - tidak yakin ada jawaban "resmi" yang mewakili kenyataan!
Tyler

Jawaban:

4

Berdasarkan Bagaimana Perubahan Dilacak dari dokumen, inilah yang terjadi:

Diagram siklus reaktivitas Vue

  1. Watcher khusus dibuat untuk instance komponen untuk menentukan kapan re-render diperlukan.

  2. Vue mengubah semua properti datamenjadi getter dan 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. Template diberikan. Selama render, panggilan ke isAwesomedibuat dari templat.
  2. Dalam tubuh isAwesome, pengambil untuk awesomeAnimalIdsdipanggil.
  3. Pengamat menetapkan ketergantungan pada awesomeAnimalIdsbidang data.
  4. Setelah batas waktu, awesomeAnimalIdsdiperbarui, yang memanggil awesomeAnimalIdssetter.
  5. Karena templat bergantung pada databidang yang menerima pemberitahuan, re-render dipicu.
  6. Ulangi langkah (3).

Dari contoh ini dan ini di atas, kita dapat menyimpulkan yang berikut:

Panggilan metode yang dibuat dari Templat menetapkan ketergantungan reaktif pada subset databidang yang digunakan dalam tumpukan panggilan metode. Jika bidang yang mendasarinya diperbarui, itu akan memicu re-render komponen.

Ada kesalahpahaman umum bahwa metode "dipanggil hanya sekali" atau "jalankan dan lupakan" ketika dipanggil dari templat. Ini jelas tidak selalu terjadi karena metode dapat membangun ketergantungan reaktif .

Jadi kapan kita harus menggunakan properti yang dikomputasi vs sebuah metode?

Lihat bagian panduan tentang Caching Terkomputasi vs Metode . Inilah pendapat saya:

  • Properti yang dihitung hanya akan mengevaluasi kembali ketika dependensi reaktifnya telah berubah. Yaitu menggunakan caching untuk meningkatkan efisiensi.
  • Properti yang dikomputasi harus bebas efek samping. Misalnya Anda tidak boleh menelepon fetchdari mereka.
  • Selalu lebih suka properti yang dikomputasi daripada metode jika memungkinkan untuk alasan efisiensi.
  • Gunakan metode jika Anda memiliki efek samping atau jika Anda harus menyampaikan argumen (seperti yang terlihat pada pertanyaan awal).
David Weldon
sumber
Penjelasan jelas yang bagus, terima kasih.
Ackroydd
4

Tidak, metode tidak reaktif. Hanya data yang dapat reaktif dalam Vue.

TAPI penting untuk memahami bagaimana Vue bekerja ...

  1. Vue akan mengambil templat Anda, mengkompilasinya menjadi fungsi render dan menjalankan fungsi render
  2. Saat fungsi render sedang berjalan, Vue memonitor semua data()anggota (ia melakukan ini setiap saat, tidak hanya selama render pertama). Jika ada data yang diakses selama render, Vue tahu bahwa konten anggota data ini memengaruhi hasil rendering.
  3. Vue menggunakan pengetahuan yang dikumpulkan pada langkah 2. Setiap kali anggota data "menyentuh" ​​selama rendering perubahan, ia tahu re-render harus terjadi dan melakukan hal itu ...

Tidak masalah jika Anda mereferensikan anggota data secara langsung, menggunakannya dalam computedatau dalam a method. Jika data "disentuh" ​​selama proses render, perubahan data akan memicu render ulang di masa mendatang ...

Michal Levý
sumber
1

Ini adalah kasus yang sangat menarik.

Dari apa yang telah saya baca dan pengalaman saya, saya dapat mengatakan bahwa: Tidak, metode pada dasarnya tidak reaktif. Suatu metode harus secara eksplisit dipanggil untuk dieksekusi.

Tapi, bagaimana saya bisa menjelaskan kasus Anda? Saya memasukkan kode Anda di kotak pasir dan tentu saja, ketika Anda mendorong id ke dalam array, template memperbarui untuk menampilkan nama hewan. Ini akan menunjukkan beberapa reaktivitas. Apa yang menyebabkannya?

Ya, saya menjalankan percobaan. Saya menambahkan sederhana divuntuk setiap loop yang menghasilkan angka acak ketika dibuat.

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

Dan yang saya lihat adalah bahwa setiap kali id ​​baru didorong ke dalam array, semua angka acak akan berubah. Ini adalah kunci untuk memahami mengapa "tampaknya" seolah-olah metode isAwesomeini reaktif.

Entah bagaimana, ketika ID baru didorong ke array, Vue membuat ulang loop secara keseluruhan, karenanya mengeksekusi metode lagi. Saya tidak dapat menjelaskan cara kerja bagian dalam mengapa vue mengubah seluruh loop, yang akan membutuhkan penelitian lebih lanjut.

Jadi, untuk menjawab pertanyaanmu. isAwesometidak reaktif, itu hanya ilusi yang diciptakan oleh re-render loop.

T. Pendek
sumber
1
itu benar untuk setiap properti yang dapat diamati dalam komponen (prop / data / dihitung). setiap kali mereka diubah itu memicu updateyang menyebabkan re-renderdan memicu metode apa pun yang terikat dalam template
Ohgodwhy