Replies: 1 comment
-
I personally have always liked the dollar sign to indicate a reactive variable. with runes, sure you can see that its reactive by reading wherever it is getting defined, but down the train, it was nice to be able to know clearly which variables were reactive vs which were not - dollar sign for the win IMO I would imagine runes didn't go this route primarily for compatibility with stores. Not sure if its a big deal to use $ for both stores and runes, but seeing as how we're in that awkward state of even having both stores and runes, they probably wanted to differentiate them clearly. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
This is just a random idea I had that might make sense for Svelte 6 (probably too late for 5) - it might be trash but still, thought it might be worth writing for a discussion.
The problem
The issue with Svelte has always been figuring out what state is reactive. It's not hard or complicated, it's just not always intuitive, making it an issue mostly for beginners or otherwise very rarely a problem. Regardless, Svelte 4 was full of "magic" that didn't have an explicit shape, instead relying on various native JS syntaxes like
export let
, for props,export const/function
for instance properties,this
for the occasional Svelte prop with multiple meaning (<svelte:component this={A} bind:this={B} />
), and of course$:
for reactive statements.Svelte 5 set out to fix this by using runes - these mark exactly where the compiler will interact with your code. Except that it's not, and it has a few issues. Number one is exactly what it set out to fix - it's still somewhat confusing what variables are reactive. Overall there are a few problems:
$state
should cross function boundaries, like stores, but it doesn't - Update of $state variable overwrites it instead of update #13306get()
properties just to achieve cross-function reactivity - Passing reactive values to functions #12800, Add $readable and $writable runes #9237$state
” warning #13102, Svelte 5: Confusing and unclear warningstate_referenced_locally
#11883, state_referenced_locally warning when trying to store an initial value #12877T
, but under the hood it's something likeSvelteState<T>
- Class state has a fundamental typing flaw #12655The light at the end of the tunnel
The title of this heading is somewhat dramatic, but there has always been one part of Svelte that, while the docs claim is "confusing" and "requires some learning", to me felt like the most intuitive and clear part of Svelte: stores. It's the simplest thing, really - declare it with
writable
to create state and withderived
to create derived state. It's all pure Javascript (when in doubt, just use your IDE to check out the source code ofwritable
), it updates syncronously, and you can even write your own, as it has a very simple contract. It's also very easy to connect external data to a store usingreadable
, and the start-stop notifier system is great to ensure no unneeded computations are done on stores no one is subscribed to.It also has the right amount of "magic" and it's very easy to understand - prefix with
$
to subscribe to the value:store
is just the store,$store
is the reactive value. The compiler only intervenes when it sees the$
, and it's also easy to understand the subscription is tied to the component lifetime. When using stores, the rule is simple: the value is reactive when prefixed with$
.You can also pass stores to plain-JS files, and unlike $state/$effect, which when used in
.svelte.js
files can be problematic, stores are simple by nature - it's up to you when you call unsubscribe to avoid lifecycle-binding issues. It's also worth noting stores have none of the problems of rune-based state, enumerated above.The idea
Take everything good from stores and merge it with everything good from the rune-based state. The ergonomics of stores with all of the advantages of runes, like proxies, nested reactivity, and more.
Component.svelte
other.svelte.js
And beyond?
This is already far-fetched, but maybe this could allow Svelte state to interop with (existing) plain JS by having it implement store contract by giving it a
subscribe()
method (andset()
for writable states). I would even suggest aget()
method as they don't have the start-stop notifier system.What this would solve (Upsides)
Also considering the idea above (get, set and subscribe methods), this would solve a lot of problems:
$
= reactive will be the only law. Warnings likex is updated, but is not declared with $state(...). Changing its value will not correctly trigger updates
would no longer be needed. The user intuitively knows the change won't trigger updates since they wrotex = ...
, not$x = ...
. It will also be impossible to accidentally lose reactivity. Say, for example, a function takes aUser
object and you have aUser
state variable. Writingf(state)
will give you a type error -State<User> is not assignable to User
. If you writef($state)
it's clear the reactivity part happens right before the function call - this might be ok in a template. Otherwise, modify the function to receive a state or use$derived(f($state))
.set
function, we simply tell them "$ = set", they won't need to figure out what is reactive.untrack()
would no longer be needed, simply don't use$
if you don't want reactivity -get(store)
,state.get()
. We also wouldn't needfromStore
/toStore
anymore.const x = someFunc(() => a, () => b); x.value
will becomeconst x = someFunc(a, b); $x
. Not to mention the ability to interact with non-svelte files, and with potentially existing store-based code.Downsides
We have to use dollar signs everywhere, we don't like that. But, is it that bad? It has worked wonderfully with stores all this time, so why wouldn't it work here too?
Beta Was this translation helpful? Give feedback.
All reactions