Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix class setters invocation on nested x-data #4528

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

helio3197
Copy link

The current implementation of the set trap in mergeProxies restricts key lookup to the target's own property keys. This prevents class setters defined in the target's prototype from being called when there is more than one object in the x-data stack.

This allows components like this to work:

<script>
  class BaseHandler {
    _prop = 'original'
  
    get prop() {
      return this._prop
    }
  
    set prop(v)  {
      this._prop = v
    }
  }
  window.baseHandler = () => new BaseHandler()
</script>

<div x-data>
  <div x-data="baseHandler()">
    <button x-text="prop" @click="prop = 'edited'"></button>
  </div>
</div>

@ekwoka
Copy link
Contributor

ekwoka commented Feb 12, 2025

I'm not sure how the test demonstrates the issue.

You have code related to prototype chain but the test doesn't use the prototype chain at all.

@helio3197
Copy link
Author

It does, because the setter function is defined in the class instance's prototype not in the instance object itself, then when the setter is invoked e.g. value = 'somevalue' the current proxy's set trap won't be able to set the property value, because there is a check asserting that the invoked key must be an own property of the target (Object.prototype.hasOwnProperty.call(obj, name)) which evaluates to false in this case because the property itself is a getter and setter defined in the class instance prototype.

You can check the live issue in this codepen, and here is the same example with the implemented change.

@ekwoka
Copy link
Contributor

ekwoka commented Feb 13, 2025

Okay, and it bypasses the vue reactivity bug since it's a class setter and not own setter?

@helio3197
Copy link
Author

No, I had not considered the scenario described by this PR, therefore referencing other parent data-stack objects will result in error. However, I've modified the code to use the prototype, where the setter is defined as the 'target'. Thus, this check can pass, and the setter method can be called with the mergeProxy as the this value.

const descriptor = Object.getOwnPropertyDescriptor(target, name);
        if (descriptor?.set && descriptor?.get)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants