The ValtioProxy Superclass Pattern (and its limitations) #759
pastelmind
started this conversation in
Ideas
Replies: 1 comment 1 reply
-
cool solution 👍 |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I discovered a useful pattern for class-based state, using a trick called return overriding:
Benefits
Simply Reactive
Any class that inherits
ValtioProxy
is reactive by default:Eliminates
this
confusionIn ordinary classes, the
this
keyword is tricky because sometimes it is a proxy, but sometimes it is not.This can be problematic when you want to exclude some classes from the proxy state tree with
ref()
, but still let them access other state:Passing
proxy(this)
tonew Pet()
does not solve the problem. (click to see why)Suppose we pass
proxy(this)
to thePet
constructor:What happened? When we invoked
proxy(new Person())
, the following happens:Person
is constructed.name
is initialized on thePerson
instance.pet
is initialized on thePerson
instance.proxy(this)
is invoked. It created a new proxy by copying all properties onthis
to a new object. Notice that theage
field is not initialized yet.Pet
is instantiated.age
is initialized on thePerson
instance.proxy()
receives the createdPerson
instance. Since it is the same instance passed in theproxy(this)
call, it returned the cached proxy object (which is missingage
).person
with noage
.This can be avoided by moving
pet
to the bottom of the class body:But it still does not fix the problem:
person.pet
is missing, because it was not onthis
when it was initialized. It's a chicken-and-egg problem.This can be solved by using
ValtioProxy
:Limitations
When using ES2022 class fields, objects and arrays are not made reactive:
This is because ES2022 class fields use
Object.defineProperty()
semantics, and therefore do not invoke theset
trap of Valtio's proxy object.One workaround is to initialize objects and arrays in the constructor:
It would be nice if we don't have to care about this, though.
Feature suggestion: Support ES2022 class field initialization
Would it be possible to support class fields as reactive properties, even when they are objects or arrays? Yes, if we add a
defineProperty
trap to Valtio's proxy that invokes our listeners.Intercepting all possible
defineProperty
calls is too big a task. For now, we can focus on true class fields, which are always CEW (configurable, enumerable, and writable). We could limit the trap to creating CEW own properties, and only if (1) either the property does not exist, or (2) if an own property exists and is also CEW.I have submitted a pull request for this. (#760) Feedback is welcome!
Beta Was this translation helpful? Give feedback.
All reactions