-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Provide the default store implementations as classes #7193
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
Comments
I don't think we want to have two ways of doing the same thing. The default store implementations are just examples that could well live in userland. Nothing is really an integral part of the framework apart from the store contact. If someone wanted to publish their own store classes that they feel make it easier to create stores, they're of course free to do so. Add long as the resultant objects abide by the store contact, it wouldn't matter where they came from. |
That's right, I'm definitely aware that you can create these classes yourself if you want, but that means you'd then have to mostly duplicate the work already done here. And that doesn't make much sense. My suggestion here is that I think it would be very useful if Svelte provided its standard, canonical implementation of stores as classes that could then be extended by users, and also if it started promoting this as the recommended way to create custom stores, since as I explained, this is in fact the superior approach. |
Seems like a duplicate of #6640 |
Well, kind of. |
I agree that
It does look like a class would make the implementation cleaner, though it relies on the fact that we know the Though with all these said, I don't think classes are bad. There are trade-off between classes and functions, e.g. classes can't be spreaded. And in my experience, I don't always extend a store, my custom function may use multiple stores in which the syntax between classes and functions aren't much different. For now, I think a better path is to implement these class alternative in userland first, and if it proves to be more handy than functions, then this proposal would have a solid start from the get-go. |
Closing as won't do - as pointed out, Svelte stores are more of a reference implementation and people are free to create their own. Also, Svelte 5 makes stores less prominent because universal reactivity can be coded with runes. |
Uh oh!
There was an error while loading. Please reload this page.
Describe the problem
Rationale:
As someone who has written quite a number of rather complex custom stores, two fundamental pain points have been the lack of polymorphism and lack of access to the store's current value in the custom store's implementation.
Because of this, I'm proposing that the default store implementation be provided as a class, precisely because this makes possible the two aforementioned scenarios.
Some real-world use cases wherein polymorphism and current value access would be essential to building certain custom stores are described below:
1. Access to the current value without subscription
This is a very common requirement. Imagine a
timer
function that returns a custom store that represents a countdown timer:As you can see, we're using the
get()
function here (imported fromsvelte/store
) each time we need the current value of the underlying store. However, theget()
function is inefficient, as explained here in the docs:So, in an example like the timer where we do have a "hot code path", (namely inside the
setInterval
callback, which is going to be executed every 50 milliseconds), this inefficiency is especially significant.You might also think: "Well, we can't we just subscribe to the underlying store in our function?!"
Well, we can, but that would mean the underlying store will always have at least one subscriber, which in turn means that the function you return from the
start
callback, which only runs once when the last subscriber unsubscribes, will never be called. So this is certainly not a feasible solution either.The
writable
function currently does store the current value as a local variable:svelte/src/runtime/store/index.ts
Lines 68 to 70 in e460acc
which of course means it doesn't expose it to the outside. If this, however, was a class, this variable could've been exposed as a
protected
property, which would give access to it to deriving classes, and that would beautifully solve this problem.Note that various (ugly) workarounds like this are currently being used across the Svelte ecosystem, here's an example.
2. Polymorphism
Suppose you want to write a function that creates a writable store whose value is synchronized across all the open tabs (or browsing contexts, to be more accurate).
This looks simple and straightforward. There is, however, a subtle bug in here: If the user of the returned store uses the
update
function to set a new value for the store, the value would NOT be synchronized. Why? Because our overridden customset
method, which in turn callschannel.postMessage(...)
isn't called, even though the built-inupdate
method does callset
internally:svelte/src/runtime/store/index.ts
Lines 87 to 89 in e460acc
since there's no polymorphism when we're dealing with plain objects like this, it's actually the default
set
function thatupdate
is calling, and not the overridden/custom one.This means we'd have to implement a very awkward custom
update
function too:If, however, the default store implementation was a class that could be extended, we could've simply overridden the
set
function, and then whenever theupdate
function callsset
internally, polymorphism would kick in and everything would work as expected:Which one is cleaner? I reckon the difference is clear.
Describe the proposed solution
What I'd suggest we do is extract the default store implementation, which currently resides in the
writable
function here, into two classes (Store
, andReadonlyStore
to differentiate them from theWritable
andReadable
interfaces, maybe? This is debatable though), and also keep thewritable
andreadable
functions, so as to avoid any breaking-change.The
writable
function could still continue to be used whenever you want to simply create a store, and the new class, on the other hand, would be meant to be extended and used for creating custom stores.And again, this change would not be breaking.
Regarding what would change in the tutorial, all I would change is the tutorial on custom stores, to start talking about these classes and how they are what should be used when creating custom stores.
Alternatives considered
As I mentioned, currently you have to utilize dirty workarounds to make up for these fundamental limitations, such as the ones I demonstrated above. So, this would indeed make creating custom stores much more efficient and developer-friendly.
Importance
would make my life easier
The text was updated successfully, but these errors were encountered: