For AI agents: the complete documentation index is available at https://nhanbe.id.vn/llms.txt, the full documentation bundle is available at https://nhanbe.id.vn/llms-full.txt, and this page is available as Markdown at https://nhanbe.id.vn/frontend/vue2.7/computed-methods-and-watch.md.

Comparing computed properties, methods, and watchers in Vue 2.7.

Computed Methods and Watch

Ba option này đều khai báo trong options object của component nhưng phục vụ ba mục đích khác nhau:

  • computed: tạo ra derived state (giá trị mới tính từ state khác), có cache.
  • methods: hàm thực thi theo yêu cầu (event handler, gọi trực tiếp trong template).
  • watch: chạy side effect khi một state thay đổi.

Computed

Tạo giá trị tính toán dựa trên reactive state (data, props, hoặc computed khác). Vue tự cập nhật khi dependency thay đổi.

Caching

Computed có cache theo dependency: chỉ tính lại khi một trong các reactive dependency của nó đổi. Truy cập nhiều lần mà dependency không đổi thì trả về giá trị cache, không chạy lại getter.

computed: {
  expensiveCalculation() {
    console.log('computed chạy')
    return this.items.reduce((a, b) => a + b, 0)
  }
}
{{ expensiveCalculation }}
{{ expensiveCalculation }}
{{ expensiveCalculation }}

Nếu items không đổi, getter chỉ chạy 1 lần. Hai lần truy cập sau lấy từ cache. Đây là điểm khác cốt lõi so với methods (methods chạy lại mỗi lần render).

Cú pháp getter-only

Dạng phổ biến nhất, chỉ đọc:

export default {
  data() {
    return {
      firstName: 'Nhan',
      lastName: 'Nguyen'
    }
  },
  computed: {
    fullName() {
      return this.firstName + ' ' + this.lastName
    }
  }
}
<p>{{ fullName }}</p>

Cú pháp getter + setter

Computed có thể ghi được khi khai báo dạng object với get và set. Setter chạy khi gán giá trị cho computed.

computed: {
  fullName: {
    get() {
      return this.firstName + ' ' + this.lastName
    },
    set(value) {
      const parts = value.split(' ')
      this.firstName = parts[0]
      this.lastName = parts[1]
    }
  }
}
this.fullName = 'Tran Van'

this.firstName // 'Tran'
this.lastName  // 'Van'

Trường hợp dùng setter thường gặp: bind computed vào v-model (input cần ghi ngược về state nguồn).

<input v-model="fullName">

Khi nào dùng computed

  • Biến đổi state để hiển thị (format, ghép chuỗi).
  • Filter / sort danh sách.
  • Combine nhiều state thành một giá trị.
  • Bất kỳ derived state nào cần dùng lại nhiều nơi.

Ví dụ filter list theo keyword:

data() {
  return {
    keyword: '',
    users: [
      { name: 'An' },
      { name: 'Binh' },
      { name: 'Cuong' }
    ]
  }
},
computed: {
  filteredUsers() {
    return this.users.filter(user =>
      user.name.toLowerCase().includes(this.keyword.toLowerCase())
    )
  }
}
<input v-model="keyword">

<ul>
  <li v-for="user in filteredUsers" :key="user.name">
    {{ user.name }}
  </li>
</ul>

Lưu ý

Getter của computed phải là hàm thuần (pure): chỉ tính và trả về giá trị, không gây side effect (không gọi API, không mutate state khác, không thao tác DOM). Cần side effect thì dùng watch hoặc methods.

Methods

methods là các hàm gắn vào instance. Dùng cho event handler hoặc khi cần gọi logic chủ động.

methods: {
  increment() {
    this.count++
  },
  formatPrice(value) {
    return value.toLocaleString('vi-VN') + ' đ'
  }
}
<button @click="increment">+1</button>
<span>{{ formatPrice(product.price) }}</span>

Khác biệt quan trọng so với computed: method không có cache. Mỗi lần component re-render, mọi method gọi trong template đều chạy lại.

<!-- chạy lại mỗi lần re-render, kể cả khi product.price không đổi -->
{{ formatPrice(product.price) }}

<!-- chạy lại chỉ khi dependency đổi (có cache) -->
{{ formattedPrice }}

Quy tắc chọn: giá trị hiển thị dẫn xuất từ state thì ưu tiên computed; hành động cần truyền tham số hoặc kích hoạt bởi event thì dùng methods.

Watch

watch theo dõi một reactive source và chạy callback (side effect) khi giá trị đổi. Khác computed ở chỗ computed tạo ra giá trị mới, còn watch thực thi hành động.

Các side effect thường gặp:

  • Gọi API khi giá trị đổi.
  • Debounce search.
  • Lưu localStorage.
  • Validate form.
  • Tracking / log.
  • Trigger animation.

Cú pháp cơ bản

Key của watch là tên property cần theo dõi. Callback nhận (newValue, oldValue).

data() {
  return { keyword: '' }
},
watch: {
  keyword(newVal, oldVal) {
    console.log(`keyword: ${oldVal} -> ${newVal}`)
  }
}

Options: immediate và deep

Dạng object cho phép thêm option:

  • immediate: true: chạy handler ngay khi component khởi tạo (không cần đợi giá trị đổi). Dùng để load data lần đầu.
  • deep: true: theo dõi thay đổi sâu bên trong object/array (mặc định watch chỉ phát hiện khi tham chiếu thay đổi).
watch: {
  filters: {
    handler(newVal) {
      this.fetchData(newVal)
    },
    immediate: true, // chạy ngay lần đầu
    deep: true       // theo dõi thay đổi bên trong object filters
  }
}

deep tốn chi phí vì Vue phải duyệt toàn bộ object. Nếu chỉ cần một field, watch trực tiếp field đó bằng chuỗi path:

watch: {
  'filters.status'(newVal) {
    this.fetchData()
  }
}
data() {
  return { keyword: '', results: [] }
},
watch: {
  keyword(newVal) {
    clearTimeout(this._timer)
    this._timer = setTimeout(() => {
      this.search(newVal)
    }, 300)
  }
},
methods: {
  async search(q) {
    const res = await fetch(`/api/search?q=${encodeURIComponent(q)}`)
    this.results = await res.json()
  }
}

vm.$watch

Có thể tạo watcher động bằng vm.$watch, trả về hàm để hủy watch:

const unwatch = this.$watch('keyword', (newVal) => {
  console.log(newVal)
})

// hủy theo dõi khi không cần nữa
unwatch()

So sánh Computed vs Methods vs Watch

Tiêu chícomputedmethodswatch
Mục đíchTạo derived stateThực thi logic theo yêu cầuChạy side effect khi state đổi
CacheCó, theo dependencyKhôngKhông áp dụng
Trả về giá trịCó (dùng trong template)Có (gọi thủ công)Không (chạy callback)
Gọi trong template{{ value }}{{ fn() }} hoặc @event="fn"Không trực tiếp
Side effectKhông nênCó thểMục đích chính
Nhận tham sốKhôngCóNhận newVal/oldVal

Quy tắc nhanh:

  • Cần giá trị hiển thị tính từ state: computed.
  • Cần hành động khi user tương tác hoặc cần truyền tham số: methods.
  • Cần phản ứng (gọi API, debounce, ghi localStorage) khi state đổi: watch.