Parse-SDK-JS icon indicating copy to clipboard operation
Parse-SDK-JS copied to clipboard

Create 'reactive' representation of state of datat in Parse.Object eg for use in libraries like React, VueJS, etc

Open tremendus opened this issue 3 years ago • 2 comments

Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] Front end libraries like Vue and React are 'reactive' front end libraries that support the automatic update to the UI when underlying data behind the UI changes. (eg. completing a task changes the status icon and label). To work, they require a POJO-like object to bind to. In the case of Vue v2, it creates getters/setters to the object. in Vue 3 it's proxies. I'm not sure about react.

The problem: Parse.Object only exposes a frozen object (object.attributes) or the get() method, neither of which can be bound in Vue (or React, so I gather). This limits the usefulness of Parse in front end frameworks like Vue and React that rely on and offer data binding.

Describe the solution you'd like A clear and concise description of what you want to happen. Parse.Object should expose an representation of the current state in the underlying data that can be bound to. Changes to this representation should flow back to the underlying state

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered. As a prototype for a demo/proof of concept I'm working on, I've created a custom class extension to the Parse.Object that essentially proxies the various set methods (set, setACL, etc) to proxy the request to both the Parse.Object and a POJO bound at this._data.

Additional context Add any other context or screenshots about the feature request here. I would imagine that with the popularity of React and Vue and friends that adding such a feature would increase the appeal of Parse to these users. It's a big limitation and a bit of a difficult one to overcome - for various reasons - by proxying the set/get methods. A more robust solution could be created if it came from within the Parse internals.

tremendus avatar Mar 11 '21 16:03 tremendus

@dblythy I remember you were using .toJSON() for binding and recently did a PR for subclassing to use with Vue. Do you have any ideas to help with this issue / feature?

dplewis avatar Mar 11 '21 23:03 dplewis

Hey Diamond,

Previously I was using toJSON to pass all the fields to Vue from the Parse Object, and then using the new dirty method in fromJSON to override it would look something like this:

<input type="text" placeholder="Monster Name" v-model="monster.name"/>
<button @click="saveMonster">Save</button>
...
data() {
  return {
     monster: {};
  }
},
async created() {
  const query = new Parse.Query('Monster');
  const monster = await query.first();
  this.monster = monster.toJSON();
},
methods: {
  async saveMonster() {
     const monster = new Parse.Object.fromJSON(this.monster, false, true);
     await monster.save();
  }
}

Now here, if you could use dot notation on a Parse.Object, you would save a large amount of code.

I've written a little subclass that should give you a rough idea of how the behaviour needs to be for VueJS.

This allows for the following code to get and set the field "name" on the "monster" Parse Object.

<input type="text" placeholder="Monster Name" v-model="monster.name"/>
/* so you could build a whole form input without needing to worry about getting and setting the fields. */
<button @click="monster.save()">Save</button>

I'm not sure if this behaviour should be added to the core JS SDK.

The problem is that it would be convenient to be able to get/set a Parse Objects fields using const field = object.fieldName, or object.fieldName = field.

In my subclass, I override _finishFetch and set the properties directly on the Parse Object. This allows me to set a input, for example, to object.fieldName. If object is updated via LQ for example or a manual fetch, _finishFetch should still be called. I then override .save to properly .set the keys so that the data is updated on the server.

I'm not sure if this approach is the "best" way for the core package, as setting every field will increase the size of a Parse Object in memory.

Other ideas:

  • Return a "Proxy" instead of a Parse Object. This allows you to intercept setting properties with unknown names to the Parse Object. However, this doesn't seem to work with VueJS as Vue uses proxies internally.
  • Allow mutating of .attributes. If attributes are mutated, update the fields and save.

dblythy avatar Mar 12 '21 03:03 dblythy

We are looking at introducing this via #1484

dblythy avatar Mar 15 '23 23:03 dblythy