Watchers của Vue.js – Theo dõi và phản hồi dữ liệu

3 min read

Watchers cho phép bạn theo dõi sự thay đổi của các biến ref, reactive, hoặc bất kỳ biểu thức tính toán nào – từ đó thực hiện các hành động như gọi API, cập nhật UI, hoặc đồng bộ dữ liệu.

Watchers là gì?

Watchers trong Vue.js là một phương pháp để theo dõi và phản ứng với sự thay đổi của giá trị reactive. Bạn có thể coi nó như một “tai nghe” dữ liệu: khi giá trị được “nghe” thay đổi, callback sẽ được gọi.

Vue 3 cung cấp hai dạng watchers chính:

  • watch: Dùng để theo dõi một hoặc nhiều source cụ thể, chẳng hạn như một biến ref, một property trong reactive, hoặc một getter trả về giá trị cần theo dõi.
  • watchEffect: Tự động theo dõi tất cả các biến được sử dụng trong một hàm callback. Khi bất kỳ biến nào trong hàm thay đổi, toàn bộ callback sẽ được chạy lại. Đây là dạng watcher đơn giản nhưng cũng mạnh mẽ.

Cú pháp và cách sử dụng watch

import { ref, watch } from 'vue';

const count = ref(0);

watch(count, (newVal, oldVal) => {
  console.log(`Count thay đổi từ ${oldVal} → ${newVal}`);
});

Các tham số chính:

watch(source, callback, options?)
  • source: Biến ref, object reactive, getter hoặc array chứa nhiều source.
  • callback: Hàm chạy khi source thay đổi. Có dạng (newValue, oldValue) => { ... }
  • options (tùy chọn): Thêm cấu hình như deep, immediate.

Các loại source trong watch

Vue hỗ trợ nhiều kiểu source cho watcher, tùy vào mục đích của bạn:

Ref

const name = ref('Vue');

watch(name, (newVal) => {
  console.log('Tên mới:', newVal);
});

Getter function

const user = reactive({ first: 'Vue', last: 'JS' });

watch(() => user.first, (newFirst) => {
  console.log('First name:', newFirst);
});

Mảng nhiều source

watch([count, () => user.first], ([newCount, newFirst]) => {
  console.log('Count:', newCount, '| First:', newFirst);
});

Mảng rất hữu ích khi bạn muốn theo dõi nhiều biến một lúc mà không cần viết nhiều watch.

deepimmediate trong watch

deep: Theo dõi sâu cho object/phức hợp

Mặc định, watch không phát hiện thay đổi sâu bên trong object. Dùng deep: true nếu bạn muốn theo dõi cả thay đổi lồng nhau.

const profile = reactive({
  name: 'Vue',
  address: {
    city: 'Quy Nhơn'
  }
});

watch(profile, () => {
  console.log('Profile thay đổi');
}, { deep: true });

Nếu không có deep: true, thay đổi profile.address.city sẽ không kích hoạt watcher.

immediate: Gọi ngay lần đầu

Khi immediate: true, callback sẽ được gọi ngay lập tức khi watcher được đăng ký, thay vì chờ đến khi giá trị thay đổi.

watch(count, (newVal) => {
  console.log('Count mới (ngay lập tức):', newVal);
}, { immediate: true });

Điều này hữu ích khi bạn muốn khởi tạo dữ liệu từ đầu (ví dụ: gọi API với giá trị ban đầu).

watchEffect trong Vue 3

watchEffect là gì?

watchEffect tự động chạy một hàm và theo dõi tất cả các biến reactive được sử dụng trong hàm đó. Khi bất kỳ biến nào thay đổi, hàm sẽ được chạy lại.

import { ref, watchEffect } from 'vue';

const count = ref(0);

watchEffect(() => {
  console.log(`Giá trị mới: ${count.value}`);
});

Ưu điểm:

  • Không cần chỉ rõ source.
  • Gọn gàng, ngắn hơn watch.

Lưu ý:

  • watchEffect có thể chạy nhiều lần hơn bạn nghĩ, đặc biệt nếu bạn sử dụng nhiều biến hoặc dependency phức tạp.
  • Không dùng khi bạn cần so sánh newVal, oldVal – vì watchEffect không cung cấp chúng.

Khi nào dùng watch vs watchEffect?

Tình huốngDùng watchDùng watchEffect
Cần truy cập oldValueCó thểKhông hỗ trợ
Theo dõi nhiều biến cụ thểCó thểPhải truy cập trong hàm
Code đơn giản, nhanh gọnDài dòng hơnNgắn gọn
Xử lý side effects như APIChính xácNhanh (nhưng cần cẩn trọng)

Tổng kết

Watchers trong Vue.js là công cụ mạnh mẽ giúp bạn:

  • Theo dõi giá trị thay đổi và phản hồi kịp thời.
  • Đồng bộ dữ liệu giữa component hoặc với server.
  • Tối ưu UI dựa trên trạng thái reactive.

Ghi nhớ:

  • Dùng watch khi cần chi tiết, rõ ràng, có thể lấy oldValue.
  • Dùng watchEffect khi bạn muốn code ngắn, tự động, đơn giản hóa logic.
  • Kết hợp deep, immediate để kiểm soát behavior phù hợp với nhu cầu.
Avatar photo

Leave a Reply

Your email address will not be published. Required fields are marked *