Proposal: deepSignal listenable container #126
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is intended to be a solution to #4 . This proposal is generally just the meat of a library I made
preact-signal-store
, but I'd love to entirely deprecate this library and have this new primitive added to this package. I'd be certainly willing to add more tests or add to the demos website if the maintainers think that this primitive is worth having.I also would be totally receptive of reccomendations for better sorting of the types as I realize the existence of
DeepSignal
,IDeepSignal
andDeepSignalImpl
appears obtuse/excessive.I also considerred making the
value
getter onDeepSignal
return a stored privatecomputed
_value
property but honestly, I just didn't see what would be gained by this.Here's the current README.md to the package for a better description of what this offers.
How it works
Very simply, the library just takes an arbitrary object of any scale or shape, and recursively turns all properties into signals. The objects themselves each turn into a
DeepSignal
which contains avalue
getter & setter as well as apeek
method just like regularSignal
instances. However, if you assign a new value to aDeepSignal
, the setter method will recursively find every trueSignal
inside the object and assign them to a new value. So if you subscribe to aSignal
in a component, you can guarantee that it will be updated no matter what level of the store gets reassigned.So a simple example like this
...is equivalent to this code...
Using
DeepSignal
in a local contextBy utilizing
useDeepSignal
you can get a local state DX that's very similar to class components while continuing to have theperformance advantages of signals.
Recipes
Zustand style method actions
When I look to Zustand for the API it provides, it seems like a lot of their API (as much as I admire it) is based around supporting the
functional context. But the output of
preact-signal-store
is very openly dynamic and writing to it inside or outside of a componentends up being the same. So you can take Zustand's basic example...
...and create an effectively equivalent version with
preact-signal-store
like this...Storing and fetching from localStorage
Because the
value
getter on aDeepSignal
effectively calls thevalue
getter on each underlyingSignal
, calling theDeepSignal
'sgetter will properly subscribe to each underlying signal. So if you wanted to manage the side effects of any level of a
DeepSignal
youjust need to call
effect
from@preact/signals
and callDeepSignal.value
This would also work for any level of the
DeepSignal
.This should fulfill most needs for middleware or plugins. If this fails to meet your needs, please file an
issue and I will address the particular ask.
TypeScript support
The API for
deepStore
anduseDeepStore
will handle dynamic typing for arbitrary input! It will also help you avoid a case like this