React doesn’t really concern itself with state management. Of course it has context, state, and props but the mental model for it predates focus on fine grained reactivity in frontends — useSyncExternalStore helps enable others to fill that void in v17+. Fine grained reactivity was notably also missed in the development of web components — only now is there a tc39 proposal for signals (in its early stages).
Jotai, mentioned briefly in the article, may not be built in but is as intuitive as signals get and isn’t even tied to React as of later versions.
I’ve very rarely met a state management problem in clientside state management where neither tanstack query (for io related state) nor jotai (for everything else) are the best answer technically speaking. The rare exceptions are usually best served by xstate if you want to model things with FSMs or with zustand if you actually need a reducer pattern. There’s a tiny niche where redux makes sense (you want to log all state transitions or use rewind or are heavily leaning on its devtools) but it was the first to get popular and retains relevance due to the fact that everyone has used it.
You can go a long way with useContext and useReducer/useState but few would opt for alternatives if jotai came batteries included with react.
Never heard of Signals[1] until now, thanks. But it makes me nervous with how much influence it has from React and Vue, and the way React and Vue do things. These are not the be all end all methods of reactivity, and I can't help but think if there's going to be an official language feature implemented for this, there needs to be room for other voices to be heard that have zero influence from React/Vue. Maybe there's still time since it's Stage 1.
Most UIs I've written in my career benefit from being modeled as FSMs. While I see the value proposition of the atom-based approaches, especially for basic applications, I can't help but become a bit hesitant about their scalability long-term on large teams. Part of the reason the very dogmatic Redux approach of a event dispatching + single store of truth caught on so quickly was because a lot of us had felt the pain of two-way data binding / global state with event listeners in Angular 1. I distinctly remember the horror of debugging digest loops (scope.$$phase memories) and being completely lost in the unstructured data flow. What made for a great demo became a nightmare at scale.
There's nothing stopping people from using these atom-based libraries to build more robust abstractions, but from my professional experience I tend to just see global getters and setters with useEffects / lifecycle method of your frameworks choice as a side effect sync.
Maybe my instincts are off here though and I am overly cautious. I love XState but the learning curve is rather massive and getting buy in from other team members is hard when the DX of the atom approach is so nice.
I feel like state "management" and reactivity performance are talked about a lot, when ultimately state orchestration is where I see things fall over the most.
According to a resonating reddit comment, Svelte isn't more popular because it's simply too late; React and Vue got there early and got good enough, so Svelte can't really get as big as them.
I think this might be true short term, but long term it means Svelte has more room to evolve with the web and with JavaScript itself, since fewer users means more room to move fast and break things, like Zig can and does. And Zig isn't dead.
This gives me a little encouragement for my personal web reactivity project. I'm confident I came up with a reactivity model that's technically innovative, which does and is what I always wanted React to do and be. But being so late to the game, my hypothetical framework has no chance to gain traction. I say hypothetical because I haven't even started making it yet. It would be built on the Ref class[1] that came out of my experimental work on os.90s.dev, but only last night did I finally get around to experimenting with using it with HTML[2].
The concept is to have JSX transform to allowing attributes to be given MaybeRefs and if its a ref then watch it and set the attr to the value, and just return the HTMLElement itself. This should be a good enough foundation to build an entire reactive framework around.
Having almost no users is a blessing, because it gives me the complete freedom to experiment with this relatively slowly. The time between creating refs and stabilizing them was a few months. The time between stabilizing them and using them in that experiment was another month. It'll probably be another month before I get a functioning non-trivial app working with it. And another few months before it's cleaned up enough to be both generic and convenient.
Maybe this should have been a blog post. I never know.
It's neither true that Svelte has few users or that we can easily break things. Tons of sites are built with Svelte like Yahoo Finance and Apple Music. Svelte 5 was the only big change in syntax in the past five years and we made sure that there's a good migration tool, etc. to minimize the amount of hardship and upgrade might cause. As a result the majority of users have already upgraded to Svelte 5.
That being said, Svelte absolutely does continue to innovate. We'll be introducing a new async primitive, RPC mechanism, etc. in the near future: https://m.youtube.com/watch?v=1dATE70wlHc
// Create new Ref
const r = van.state(0)
// derive functions as adapt/watch/multiplex.
// Implicitly depends on any Ref it uses and re-runs when they change.
const r2 = van.derive(() => 2 * r.val)
van.derive(() => console.log('r2 is ' + r2.val))
// Changing the value doesn't update r2 or print immediately, it schedules
// a batch update when all derives will get recomputed.
r.val = 3
// ...So 'r2 is 6' won't be printed here.
r.val++
// Refs can be used in a hyperscript-style DOM builder.
// This creates a regular HTMLElement, with a regular Text node where r2 goes,
// but it holds onto that Text node behind the scenes and automatically
// updates it when r2 changes.
const {p} = van.tags
document.appendChild(p("The value is ", r2))
I would recommend to not make a web framework with the idea of it being popular, like competitive with react. It’s much better to make a library that works with react / vue / svelte and see if that can become popular.
There are enough web frameworks. If you make a blog post where you state what limits you have with the current state of web technology, and you describe it really well, I’m sure someone will be able to point out how there is a web framework that deals with that. Or a way to implement that in current web frameworks.
> The concept is to have JSX transform to allowing attributes to be given MaybeRefs, and if its a ref then watch it and set the attr to the value
That is essentially what Signals are, including directly setting .textContent when possible.
This model actually predates all of this and was used way back, in Backbone.js and other pre-react frameworks, except we didn’t have JSX or virtual DOM at the time.
I think it is useful to say the blog post is using svelte 4, and the svelte 5 docs mention:
“When to use stores
Prior to Svelte 5, stores were the go-to solution for creating cross-component reactive states or extracting logic. With runes, these use cases have greatly diminished.
when extracting logic, it’s better to take advantage of runes’ universal reactivity: You can use runes outside the top level of components and even place them into JavaScript or TypeScript files (using a .svelte.js or .svelte.ts file ending)
when creating shared state, you can create a $state object containing the values you need and then manipulate said state
state.svelte
Stores are still a good solution when you have complex asynchronous data streams or it’s important to have more manual control over updating values or listening to changes. If you’re familiar with RxJs and want to reuse that knowledge, the $ also comes in handy for you.”
I also like svelte quite a lot although I was/am genuinely a bit confused as to how to join svelte to some external [state machine / business logic]. I ended up with runes basically infecting the entire codebase, but presumably a proper boundary must be possible?
For complex things, I came up with a pattern that stores the state externally from the components in a single centralized file. So the components just become simple shells that render the state and forward events. (All the complex business logic can be tested without the DOM/headless browser.)
I call it "nation state" because it groups sets of related variables together in a scope between local and global.
I implemented the pattern with Svelte runes, but I think it could be implemented with anything; even React.
Yeah sadly the stores the author talks about here aren't the right way to do things anymore in modern svelte and they're all-in on Runes.
Stores were a big part of the reason I liked svelte; they were so conceptually simple, extensible with plain JS, and made interop outside of Svelte trivial without the Svelte magic leaking out.
They're still in Svelte, but they mix poorly with runes and are basically unsupported in runes mode. I opened up a bug about store behavior not working like it used to when mixing with runes, and the response was pretty much "yeah we don't expect it to work like that anymore when runes mode is enabled".
The problems with these examples in my opinion is they often extend extremely trivial examples of problems to large, complex applications with a lot of assumptions about the problems those large, complex applications are likely to have.
It's great that there are alternatives to React, and that they do some things better than it. But what I find is that most large, complex applications I've worked on are not in particular hindered by the choice of React as a technology. It does vary from project to project too, of course - some applications will benefit more from some kind of well designed central state management solution.
> But what I find is that most large, complex applications I've worked on are not in particular hindered by the choice of React as a technology.
AKA, React is accidental complexity. Solving accidental complexity issues may be required some time, but more often than not, it's just something you endure as the alternative choices are not that much better.
Ironic that this is one case when you don't use an apostrophe to indicate the possessing entity. I suppose the rule is possessive nouns only, not pronouns.
In my experience with data-binding, these instances of disabling the typesystem accumulated, and became a frequent source of bugs.
So even though I hope for Signals to catch on, I believe the best way of connection to them will still be React:
function Output({ userSignal }) {
const user = useSignal(userSignal)
if (!user) return <span>No user found</span>
return <span>{user.firstName} {user.lastName}</span> /* TypeScript knows that user must be defined */
}
For generic browser based application I am in favor and am using domain specific libraries like three.js and purposely made web components. For the rest modern javascript works just fine. I just do not see the value of those framework monstrosities and build processes. They might be solving some problems for companies of Meta's scale but on small dedicated teams in my opinion it is just waste of time and money for no tangible benefits.
If you're writing Svelte code today and you need shared state, I would recommend you start by looking at the Context API (https://svelte.dev/docs/svelte/context). For manual control of data updates you'll probably still want to use Stores (SvelteKit does!) but I'd start with Context first.
I had never heard of Pinia. Visited their landing page [1] and there's a button selling a course on how to use the library. There's a CTA for the course when you go to the Guide page as well. Very strange!
Svelte stores just sound like adding Redux to React, which used to be in vogue then stopped being in vogue and I guess this blog post marks them being back in vogue.
The blog post compares an example using hooks to pass in a state and update function to a child component. It then compares that to a Svelte component which contains a state variable.
Those two examples aren't equivalent because any parent component wrapping the Svelte component doesn't have access to the state whilst App (in the React example) does.
For the Svelte example to be equivalent, the component would have to export the store.
A minor gripe but the hooks vs Svelte state is pretty minor issue in itself.
svelte has earned it's place and the more people use it - the better. I couldn't find a reason to switch, same with ember in early days, same with any handlebars go/php/rust etc. We live in the era when it's enough to learn one UI framework and just ship things.
0xfffafaCrash|9 months ago
Jotai, mentioned briefly in the article, may not be built in but is as intuitive as signals get and isn’t even tied to React as of later versions.
I’ve very rarely met a state management problem in clientside state management where neither tanstack query (for io related state) nor jotai (for everything else) are the best answer technically speaking. The rare exceptions are usually best served by xstate if you want to model things with FSMs or with zustand if you actually need a reducer pattern. There’s a tiny niche where redux makes sense (you want to log all state transitions or use rewind or are heavily leaning on its devtools) but it was the first to get popular and retains relevance due to the fact that everyone has used it.
You can go a long way with useContext and useReducer/useState but few would opt for alternatives if jotai came batteries included with react.
90s_dev|9 months ago
[1] https://github.com/tc39/proposal-signals
Stoids|9 months ago
There's nothing stopping people from using these atom-based libraries to build more robust abstractions, but from my professional experience I tend to just see global getters and setters with useEffects / lifecycle method of your frameworks choice as a side effect sync.
Maybe my instincts are off here though and I am overly cautious. I love XState but the learning curve is rather massive and getting buy in from other team members is hard when the DX of the atom approach is so nice.
I feel like state "management" and reactivity performance are talked about a lot, when ultimately state orchestration is where I see things fall over the most.
unknown|9 months ago
[deleted]
nateroling|9 months ago
90s_dev|9 months ago
I think this might be true short term, but long term it means Svelte has more room to evolve with the web and with JavaScript itself, since fewer users means more room to move fast and break things, like Zig can and does. And Zig isn't dead.
This gives me a little encouragement for my personal web reactivity project. I'm confident I came up with a reactivity model that's technically innovative, which does and is what I always wanted React to do and be. But being so late to the game, my hypothetical framework has no chance to gain traction. I say hypothetical because I haven't even started making it yet. It would be built on the Ref class[1] that came out of my experimental work on os.90s.dev, but only last night did I finally get around to experimenting with using it with HTML[2].
The concept is to have JSX transform to allowing attributes to be given MaybeRefs and if its a ref then watch it and set the attr to the value, and just return the HTMLElement itself. This should be a good enough foundation to build an entire reactive framework around.
Having almost no users is a blessing, because it gives me the complete freedom to experiment with this relatively slowly. The time between creating refs and stabilizing them was a few months. The time between stabilizing them and using them in that experiment was another month. It'll probably be another month before I get a functioning non-trivial app working with it. And another few months before it's cleaned up enough to be both generic and convenient.
Maybe this should have been a blog post. I never know.
[1]: https://90s.dev/guides/refs.html
[2]: https://github.com/sdegutis/bubbles/commit/cde2bea973b22538f...
benmccann|9 months ago
That being said, Svelte absolutely does continue to innovate. We'll be introducing a new async primitive, RPC mechanism, etc. in the near future: https://m.youtube.com/watch?v=1dATE70wlHc
edflsafoiewq|9 months ago
haburka|9 months ago
There are enough web frameworks. If you make a blog post where you state what limits you have with the current state of web technology, and you describe it really well, I’m sure someone will be able to point out how there is a web framework that deals with that. Or a way to implement that in current web frameworks.
ricardobeat|9 months ago
That is essentially what Signals are, including directly setting .textContent when possible.
This model actually predates all of this and was used way back, in Backbone.js and other pre-react frameworks, except we didn’t have JSX or virtual DOM at the time.
EmilienCosson|9 months ago
“When to use stores
Prior to Svelte 5, stores were the go-to solution for creating cross-component reactive states or extracting logic. With runes, these use cases have greatly diminished.
when extracting logic, it’s better to take advantage of runes’ universal reactivity: You can use runes outside the top level of components and even place them into JavaScript or TypeScript files (using a .svelte.js or .svelte.ts file ending) when creating shared state, you can create a $state object containing the values you need and then manipulate said state state.svelte
export const userState = $state({ name: 'name', /* ... */ }); App
<script lang="ts"> import { userState } from './state.svelte.js'; </script>
<p>User name: {userState.name}</p> <button onclick={() => { userState.name = 'new name'; }}> change name </button>
Stores are still a good solution when you have complex asynchronous data streams or it’s important to have more manual control over updating values or listening to changes. If you’re familiar with RxJs and want to reuse that knowledge, the $ also comes in handy for you.”
https://svelte.dev/docs/svelte/stores#When-to-use-stores
mhh__|9 months ago
Leftium|9 months ago
I call it "nation state" because it groups sets of related variables together in a scope between local and global.
I implemented the pattern with Svelte runes, but I think it could be implemented with anything; even React.
I went into more detail here (with live example/code): https://www.reddit.com/r/sveltejs/comments/1dgf8la/comment/l...
Ameo|9 months ago
Yeah sadly the stores the author talks about here aren't the right way to do things anymore in modern svelte and they're all-in on Runes.
Stores were a big part of the reason I liked svelte; they were so conceptually simple, extensible with plain JS, and made interop outside of Svelte trivial without the Svelte magic leaking out.
They're still in Svelte, but they mix poorly with runes and are basically unsupported in runes mode. I opened up a bug about store behavior not working like it used to when mixing with runes, and the response was pretty much "yeah we don't expect it to work like that anymore when runes mode is enabled".
tonyhart7|9 months ago
and its not elegant, lets call it that way
davedx|9 months ago
It's great that there are alternatives to React, and that they do some things better than it. But what I find is that most large, complex applications I've worked on are not in particular hindered by the choice of React as a technology. It does vary from project to project too, of course - some applications will benefit more from some kind of well designed central state management solution.
skydhash|9 months ago
AKA, React is accidental complexity. Solving accidental complexity issues may be required some time, but more often than not, it's just something you endure as the alternative choices are not that much better.
pinoy420|9 months ago
[deleted]
rendall|9 months ago
> I like Svelte more than React (its store management)
tln|9 months ago
Honestly I don't love HN's title edits. Why can't we have nice blog titles that start with why?
billforsternz|9 months ago
bravesoul2|9 months ago
Easy mnemomic: the apostrophe is for a missing letter, I.
unknown|9 months ago
[deleted]
bsaul|9 months ago
okonomiyaki3000|9 months ago
SebastianKra|9 months ago
This is described in the Solid documentation: https://docs.solidjs.com/configuration/typescript#control-fl...
In my experience with data-binding, these instances of disabling the typesystem accumulated, and became a frequent source of bugs.
So even though I hope for Signals to catch on, I believe the best way of connection to them will still be React:
fabioz|9 months ago
Already__Taken|9 months ago
I think the new memo compiler address' this in the most complicated way possible.
FpUser|9 months ago
ezarowny|9 months ago
CharlieDigital|9 months ago
Pinia is so low ceremony and "just works"; it makes state management concerns practically disappear.
alabhyajindal|9 months ago
1. https://pinia.vuejs.org
fny|9 months ago
There’s an arcane layer of $yntax to mediate and a lot of flexibility and intuition is lost as a result.
__s|9 months ago
voby.js looks neat
efilife|9 months ago
philipwhiuk|9 months ago
digianarchist|9 months ago
Those two examples aren't equivalent because any parent component wrapping the Svelte component doesn't have access to the state whilst App (in the React example) does.
For the Svelte example to be equivalent, the component would have to export the store.
A minor gripe but the hooks vs Svelte state is pretty minor issue in itself.
defraudbah|9 months ago
svelte has earned it's place and the more people use it - the better. I couldn't find a reason to switch, same with ember in early days, same with any handlebars go/php/rust etc. We live in the era when it's enough to learn one UI framework and just ship things.
Good post though, I wish it had more examples so
vtemp99|9 months ago
[deleted]
piracyrules|9 months ago
[deleted]