-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Description
Describe the problem
I understand the rationale for $state not proxying non-POJO objects, but I think having non-POJO reactive state is a very useful pattern that is worth trying to support.
A very simple example (and my current use case): Part of state is a Grid which wraps a 2d array and provides helper methods like grid.at(coord: Coord). By forcing state to be only POJO, I now have to do one of:
- Use
grid[coord.row]?.[coord.col]throughout the app - Turn the helper methods into free/static functions like
Grid.at(grid, coord) - Do something like
let g = $state(foo.grid.data) // grid.data is the 2d array foo.grid.data = g // repeat for all non-POJO objects in nested state // then finally let reactiveFoo = $state(foo)
There are loads of example use-cases like this, as it's a pretty common data modeling pattern (usually a Model pattern is just "some raw data + some helper methods to access/modify the raw data").
Describe the proposed solution
For the sake of nomenclature, let's just refer to classes and class instances, though of course classes aren't the only way to create objects with a non-Object prototype.
It would be nice to allow classes to opt in to being "proxy-able", either by specifying that the proxy should wrap the entire object, or by specifying some subset of fields to be proxied.
A potential syntax: (exact naming TBD)
class Thing {
foo: number;
bar: string;
}
// Assume `$state.proxyable` is a Symbol.
// Option 1: Proxy the object, and let the user handle errors
// which originate from private/internal property accesses:
Thing.prototype[$state.proxyable] = true
// Option 2: Proxy some subset of fields from the object:
Thing.prototype[$state.proxyable] = ['foo', 'bar']Then, when proxy checks whether to wrap the object, it can also check prototype[$state.proxyable] and proceed accordingly.
Option 1 downsides: Users may hit errors resulting from private/internal property accesses, arguably making $state a slightly leakier abstraction than it currently is.
Option 2 downsides: The list of proxied fields would also have to be stored in the metadata and queried during various proxy traps, which is less than ideal from a performance perspective.
Importance
nice to have