retejs / rete

JavaScript framework for visual programming
https://retejs.org
MIT License
10.17k stars 653 forks source link

Vue 3 reactivity issue with adding inputs/outputs to node #701

Closed dlohvinov closed 7 months ago

dlohvinov commented 7 months ago

Вітаю!

I'm having an issue in my Vue 3 application adding new (dynamic) inputs or outputs to a node - they are not reactive :(

The issue is, Vue 3 uses Proxy for tracking reactivity changes, but in rete source code, new inputs or outputs are assigned using Object.defineProperty (link), which is not tracked by Proxy reactivity.

If I override this method and just set them like below, everything works fine.

addInput(key, input) {
    // super.addInput(key, input);
    this.inputs[key] = input;
  }

Is there a reason why Object.defineProperty is used, and i should be using my own override solution, or it could be fixed in rete source code?

if you want, i can make a pull request :)

Слава Україні! ❤️

Ni55aN commented 7 months ago

Героям слава!

Object.defineProperty is required to prevent name clashing for keys such as constructor, toString https://github.com/retejs/rete/commit/51c63a2335678bfec9c76c5d5f008e7b2a3cb314

There is no need to tweak this code as these objects aren't created by Vue.js and know nothing about reactivity. In such cases, just re-render the nodes (area.update('node', ...)),

dlohvinov commented 7 months ago

It didn't work: new in's/out's hadn't been adding, so I've came up with something like this:

  addInput(key, input) {
// prevent default .defineProperty behavior
    // super.addInput(key, input);

// each in/out has its own height, so i'm adding it to node height
    this.height += 50; 
    this.inputs[key] = input;

// if there's no area inside node - its default node in's/out's on initialization stage
    this.area?.resize(this.id, this.width, this.height);
  }

Thanks you for your help! :)

Ni55aN commented 7 months ago

It looks like there are other factors rather than a problem with the plugin, because if you test it on basic example, it renders the I/O successfully:

  setTimeout(() => {
    a.addOutput("b", new ClassicPreset.Output(socket));
    area.update('node', a.id)
  }, 4000)

are you using a custom node component? Does it have prop seed and inputs/outputs as a getter, not computed?