0

I've written a library that relies on equality checks. Example:

export class Item {
  constructor(opts) {
    if (typeof opts.name !== 'string') throw new TypeError('Name should be a string');
    if (!opts.name) throw new Error('Please give item a name');
    this.name = opts.name;
    this.active = typeof opts.active === 'boolean' ? opts.active : false;
  }

  activate() {
    this.active = true;
  }

  deactivate() {
    this.active = false;
  }
}

export class Stage {
  constructor(opts) {
    this.items = [];
  }
  
  add(item) {
    this.items.push(item);
  }

  activate(itemToActivate) {
    // Strict equality check here
    const found = this.items.find(i => i === itemToActivate);
    if (!found) throw new Error('Item "${itemToActivate.name}" not found');
    found.activate();
  }
}

Using this library could look like this:

import { Item, Stage } from 'lib.js';

const stage = new Stage();
const item1 = new Item({ name: 'one' });
const item2 = new Item({ name: 'two' });
stage.add(item1);
stage.add(item2);
stage.activate(item2);

This all works fine, but I'm running into issues when using this library in a framework that works with proxied objects like Vue 3, since I'm using a strict equality test in the activate method of the Stage class.

For example, in Vue 3:

<script>
import { Item, Stage } from 'lib.js';

export default {
  data() {
    return {
      stage: null,
    };
  },
  created() {
    this.stage = new Stage();
    const item1 = new Item({ name: 'one' });
    const item2 = new Item({ name: 'two' });
    stage.add(item1);
    stage.add(item2);
    stage.activate(item2); // This will throw an error `Item "two" not found`
  }
}
</script>

<template>
  <div v-if="stage">
    <div>Items:</div>
    <div v-for="(item, idx) in stage.items">{{ item.name }}</div>
  </div>
<template>

From what I understand, Vue 3 and other frameworks' use of Proxy introduce a caveat to be aware of: the proxied object is not equal to the original object in terms of identity comparison (===), which is why activate throws an Error.

My question is: how do I update my library so it supports Proxy-based frameworks without using any framework helpers like toRaw which would make my library dependent on that framework?

5
  • 1
    Once you hand your objects over to Vue3 as props, Vue3 proxies and they are no longer yours. Those proxies as part of Vue's reactivity feature set. Specifically so the props can be watched and updates provided when the props change. Since Vue is doing this, it owns the proxies and is in control, you must ask Vue to undo this and regain control of your objects to treat them as "your" objects (toRaw()). Otherwise, you'll need to Reflect on those properties and test each individually for equality. Commented Dec 20, 2022 at 20:41
  • thank you for your answer @RandyCasburn. I understand the reason behind the equality check failing due to Vue working with proxies to enable reactivity. However I'm looking for a way to update my library to support any framework that uses Proxies for reactivity, without requiring the consumer of my library to do any changes. I'm okay with the the references to Item being proxied, but I need assistance on how to circumvent the strict equality error. Commented Dec 20, 2022 at 21:16
  • You'll have to introspect the input object's properties and test each individual property for equivalence. Sorry I was not clearer. (the reference to Reflect) Commented Dec 20, 2022 at 21:18
  • What is stage? If it's the original new Stage(), it should work. If it's this.stage, you also would need to refer to this.stage.items[1] for that item that you activate. Commented Dec 21, 2022 at 1:42
  • You don’t have to do anything. If a Proxy-using library breaks on your code, it is their fault. Commented Apr 13 at 12:25

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.