Làm sao để theo dõi sự thay đổi của array theo 3 sự kiện: add, update và remove?

Xin chào mọi người, em có vấn đề mong mọi người tư vấn ạ.

Em muốn theo dõi sự thay đổi của 1 array theo 3 sự kiện: add, update và remove.

Em có giải pháp là tạo class Collection extends Array.

Nhưng khi khai báo thêm 1 method mới hay override 1 method cũ thì VueJS ko nhận ra được, method mới thì báo is not a function, override method thì ko chạy vào hàm override.

Vậy mọi người ai biết cách khắc phục vấn đề này hay có giải pháp khác thì có thể giúp em được ko ạ?

Em xin cám ơn!

Bạn có thể cho xem code được không :smiley:

Code của em đây ạ

<div id="app">
  <div>{{ colect.name() }}</div>
</div>

<script>
class Collection extends Array {
  name() {
    return 'Collection'
  }
}

const app = new Vue({
  el: '#app',
  data: {
    colect: new Collection()
  }
});

</script>

Về nguyên tắc, data trong Vue phải là plain object:

The object must be plain: native objects such as browser API objects and prototype properties are ignored. A rule of thumb is that data should just be data - it is not recommended to observe objects with their own stateful behavior.

Vì vậy, tránh dùng class hay prototyped function cho data, cho dù ban đầu nó có thể hoạt động. Trong trường hợp này, nếu chỉ để theo dõi add, update và remove thì cứ dùng array bình thường, reactivity của Vue hoàn toàn xử lí được.

Như mình thấy vì bạn new Collection() của bạn nếu bận log ra sẽ chỉ trả về [] array rỗng và Vue lấy giá trị đó cho thuộc tính colect của bạn

Vì sao bạn không sử dụng watch?

Để theo dõi sự thay đổi data , sử dụng cái này nhé :smiley:

Mình nghĩ watch ở đây cũng chịu :smiley:

Watch chỉ biết là có sự thay đổi xảy ra chứ thay đổi như thế nào thì ko biết.

Em muốn bind sang thư viện js khác chứ ko phải xử lý DOM nên cần phân biệt 3 trường hợp kia để gọi method js phù hợp

Vậy thì bạn trigger sự kiện đó khi nào, mình thấy việc viết như bạn khá là thừa thãi

Watch nhận vào new and old array, từ đó bạn có thể biết add, delete, update.

Mình cũng từng nghĩ tới việc này nhưng có lẽ sẽ phải dùng khá nhiều vòng lặp nên ko muốn lắm, hơn nữa trường hợp update thì ko biết sẽ nhận diện như thế nào?

Mình đang sử dụng Cesium và Leaflet, mình cần theo dõi 1 mảng lưu data của các tiles layers, vậy nên mình cần theo dõi nó add để gọi method addLayer hoặc addProvider tương ứng, tương tự với remove, update thì mình muốn theo dõi prop opacity để gọi method changeOpacity tương ứng

Vậy sao bạn không dùng vuex (state management) hoặc nếu có quá nhiều nơi trigger sự kiện add thì bạn gom nó lại thành 1 mối và xử lý ở đó

1 Like

Ok cám ơn mọi người đã giúp đỡ e ạ.
Có lẽ e hơi phức tạp hoá vấn đề và thừa thãi nhiều thứ, e sẽ xử lý những việc này ở mutations

Mình thì nghĩ đơn giản thế này: oldVal.length == newVal.length -> update, oldVal.length < newVal.length -> add, oldVal.length > newVal.length -> delete. Tuy nhiên có 1 note như thế này:

Note: when mutating (rather than replacing) an Object or an Array, the old value will be the same as new value because they reference the same Object/Array. Vue doesn’t keep a copy of the pre-mutate value.

Đồng ý là watch có thể làm được nhưng nó không hề rõ ràng, sau này nhìn lại liệu bạn có biết cái watch đó được làm gì hay không, thay vì sử dụng vuex sẽ trigger vào đúng như action mong muốn.

watch cũng có khả năng làm được nhưng lại không rõ ràng lắm. thay đổi như thế nào thì ko biết.

vẫn sử dụng đuợc watch bình thuờng, khai báo thêm deep: true là đuợc nhé! Còn nếu muốn theo dõi sát hơn thì dùng interval() cũng được.