padavan
padavan

Reputation: 884

Vue 3 compare references to same objects with proxy wrapper

I have Parent/child component and bind arrays of object by proxy and without proxy:

const selectedTags = ref([]);
const tags = [
    {
        id: 'efrwe',
    },
    {
        id: 'dhjhe23',
    }];

<Child :tags="tags" :selectedTags="selectedTags">

In child component i add selected element from 'tags' to 'selectedTags', its reference to object from source array!

props.selectedTags.push(tags[0]);

But then i try compare this reference on same object i return false!

console.log(tags[0] == selectedTags[0]); // false

You say "okey you try compare proxy object and clear object" but i try comapare with target of proxy and return false again!

console.log(tags[0] == selectedTags[0].target); // false
console.log(tags[0] == selectedTags.target[0]); // false

i try also with 'value'

console.log(tags[0] == selectedTags[0].value); // false
console.log(tags[0] == selectedTags.value[0]); // false

how can i compare reference of same object in vue 3 ?

I think you understand that i want do, computed that return non selected items:

let nonSelected =  computed(() =>
     props.tags.filter(t => props.selectedTags.every(s => s != t))
);

Upvotes: 1

Views: 6106

Answers (1)

Estus Flask
Estus Flask

Reputation: 222864

The problem is that tags is regular non-reactive array, and selectedTags is deeply reactive, tags[0] is regular object, and selectedTags.value[0] is reactive object, i.e. Proxy instance.

In order to discard a proxy, initial object could be retrieved with toRaw:

toRaw(tags[0]) === toRaw(selectedTags.value[0]).id

ref is unnecessary here because it's not reassigned, it could be reactive array.

But the main problem is that the reactivity of tags and selectedTags is mismatched without a reason. They should either be defined as deeply reactive arrays, e.g. (readonly or reactive), or both as shallowly reactive arrays (shallowReactive, or a combination of reactive and markRaw).

Generally there wouldn't be such problem because this approach doesn't work well with immutable objects that can be expected to be used in such places. A way to do this is to discard object equality and compare the objects by a property that identifies them, i.e. id:

tags[0].id === selectedTags[0].id

Optional chaining can be used if necessary.

As it was said, it's a bad practice to mutate a prop; this makes data flow more complicated. Instead, a child needs to emit selectedTags or a list of id to a parent.

Upvotes: 6

Related Questions