I have a class that extends Array, and as part of it, I want to intercept changes that are made to its properties, so I use Proxy, which is what I return from its constructor. It works just fine until I try to use it in my Vue component. See this example.
When the page first loads, you'll see the console log for Collection 1 in the watchEffect, which is the expected result. Then when you click the Add Filter button, you'll see that the display doesn't update and the watchEffect doesn't fire... expectation is that we'd get the console log like when the page loaded. However, if you inspect collection1, you'll see that the value was added.
Does anyone know why this doesn't work and how I can fix it? It feels like maybe my proxy is being tripped up with Vue's proxy wrapper, but I don't know enough about the internals to say that confidently.
Collection.js
export class MyCollection extends Array {
constructor(data) {
super();
this.add(data);
return new Proxy(this, {
set(target, prop, value) {
target[prop] = value;
if (prop === 'filters') {
const add = []
target.records.forEach((item) => {
if (item.id === target.filters) {
add.push(item)
}
})
target.add(add);
}
return true;
}
})
}
addFilters() {
this.filters = 1
}
add(items) {
this.length = 0;
items = Array.isArray(items) ? items : [items];
this.records = items;
console.log('here', this.records, this);
items.forEach((item) => this.push(item))
}
}
App.vue
<script setup>
import {watchEffect, computed, ref, toRaw} from "vue";
import {MyCollection} from "./Collection.js";
const collection1 = $ref(new MyCollection([{id: 1, display: 'one'}, {id: 2, display: 'two'}]));
watchEffect(() => {
console.log("wow", collection1);
});
const onClickUpdate1 =() => {
collection1.addFilters();
}
</script>
<template>
<div>
Collection 1
<button @click='onClickUpdate1'>
Add Filter
</button>
</div>
<div v-for="item in collection1" :key="item.id">
{{item.display}}
</div>
</template>