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

Vue reactivity doesn't work with ES private fields #7240

Closed
taras-turchenko-moc opened this issue Nov 29, 2022 · 8 comments
Closed

Vue reactivity doesn't work with ES private fields #7240

taras-turchenko-moc opened this issue Nov 29, 2022 · 8 comments

Comments

@taras-turchenko-moc
Copy link

taras-turchenko-moc commented Nov 29, 2022

Vue version

3.2.45

Link to minimal reproduction

https://codepen.io/taras-turchenko/pen/JjZvBep

Steps to reproduce

  1. Create a class with es private fields
  2. Make it reactive
  3. Try accessing a method that uses this private field

What is expected?

Reactivity works

What is actually happening?

It causes an error:

Uncaught TypeError: Cannot read private member #name from an object whose class did not declare it

When code is processed by babel

TypeError: attempted to get private field on non-instance at _classExtractFieldDescriptor

System Info

System:
    OS: macOS 13.0.1
    CPU: (8) arm64 Apple M1
    Memory: 76.59 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.12.0 - ~/.nvm/versions/node/v18.12.0/bin/node
    Yarn: 1.22.19 - ~/.nvm/versions/node/v18.12.0/bin/yarn
    npm: 8.19.2 - ~/.nvm/versions/node/v18.12.0/bin/npm
  Browsers:
    Chrome: 107.0.5304.121
    Firefox: 101.0
    Safari: 16.1
  npmPackages:
    vue: 3.2.45 => 3.2.45

Any additional comments?

We want to migrate a front-end project from Vue2 to Vue3 and have many classes and OOP code. We've been using private fields to encapsulate our logic for a year. Now we process private fields by babel but it reproduces as well in native & babel processed code

Stackoverflow topic: https://stackoverflow.com/a/68731963

@taras-turchenko-moc taras-turchenko-moc changed the title Vue reactivity doesn't work with es6 private fields Vue reactivity doesn't work with ES private fields Nov 29, 2022
@LinusBorg
Copy link
Member

ES6 proxies simply don't support private fields which is a huge PITA., but consequently this is unfortunately a wontfix, or rather "can't fix".

FWIW, we always recommend to use POJOs for reactive state. We need to be more explicit about this specific hard limitation in the docs, though.

@LinusBorg
Copy link
Member

LinusBorg commented Nov 29, 2022

vuejs/docs#2112 brought up some path worth exploring, maybe, so I'll reopen this for the moment.

Not really an option after. all.

FWIW, you can hack around the limitation with things like:

class X {
  #a = 'secret'
  #b = 'secret'
  getPropA = () => this.#a
  constructor() {
    this._self = markRaw({ self: this })
  }
  get getA() { return this.getPropA() }
  get getB() { return this._self.self.#b }
}

PLayground

@LinusBorg LinusBorg closed this as not planned Won't fix, can't repro, duplicate, stale Nov 29, 2022
@sgpinkus
Copy link

sgpinkus commented Jul 13, 2023

ES6 proxies simply don't support private fields which is a huge PITA.

@LinusBorg Can please elaborate on that? What's does "simply don't support" mean? The Proxy doesn't have access to private members but that's by design -- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#no_private_property_forwarding

@sgpinkus
Copy link

sgpinkus commented Jul 13, 2023

FWIW, we always recommend to use POJOs for reactive state. We need to be more explicit about this specific hard limitation in the docs, though

The docs I've read explicitly recommend adding methods for stuff:

To ensure the state-mutating logic is centralized like the state itself, it is recommended to define methods on the store with names that express the intention of the actions -- https://vuejs.org/guide/scaling-up/state-management.html#simple-state-management-with-reactivity-api

It seems like a fairly reasonable recommendation. The alternative is a very different organization of code when you've got semi complex state and procedures needed to access and mutate it. It's like Redux style state+actions.

@LinusBorg
Copy link
Member

@LinusBorg Can please elaborate on that? What's does "simply don't support" mean? The Proxy doesn't have access to private members but that's by design -- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#no_private_property_forwarding

Sure its by design - a design that means we can't classes that contain native private fields with proxies - which means such classes don't (reliably) work with our reactivity system.

@LinusBorg
Copy link
Member

LinusBorg commented Jul 13, 2023

The docs I've read explicitly recommend adding methods for stuff:

The docs you link here still use a plain object (just one with methods on it), not a class, and certainly not a class with private fields

@sgpinkus
Copy link

The docs you link here still use a plain object (just one with methods on it), not a class, and certainly not a class with private fields.

Oh OK by POJO I thought you meant something basically something JSON serializable. I'm probably using "POJO" wrong. But, isn't a class instance just an object with methods on it? By "POJO" you mean I can't use some object constructed from a class constructor?

@LinusBorg
Copy link
Member

But, isn't a class instance just an object with methods on it?

Not really. Since ES6, classes are a distinct thing in JS. One of those distinctions is: classes support native private fields.

By "POJO" you mean I can't use some object constructed from a class constructor?

I'ts recommended not to. Though using a class usually works fine as long as the classes are simple enough and only manage their own property-based state.

One thing that simply does not work - rhe thing this issue is about - is that classes with private properties dont play nice with Proxies. So they cant be used with Vue's Reactivity.

@github-actions github-actions bot locked and limited conversation to collaborators Sep 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants