I’ve been a ClojureScript developer for many years, and we (as a community) have had the pleasure of the reagent library. From the early days of react, it was basically a signals-like library with an ergonomic api. Signals are almost a requirement in ClojureScript, assume you want to do any sort of REPL-based workflows.
In the time that I’ve been using ClojureScript, the whole react community has switched to hooks. I find it so baffling - requiring your entire data structure to be contained within your component lifecycle? The thousands of calls to individual “useState” to track the same number of state items? The fact that every function is closing over historical state unless you manually tell it to change every time the variable does — and then this last bit in combination with non-linear deep equality comparisons?
I recently have been in the process of switching phrasing.app from reagent atoms to preact/signals for performance reasons (and as part of a longer horizon move from react to preact) and I have to say it’s been fantastic. Maybe 50 lines of code to replicate reagent atoms with preact/signals, all the benefits, and much much faster.
Very happy that there is react-like library so devoted to first class support of signals.
Calling hooks "traditional" in relation to signals seems fine, lest that word be relegated in time to whatever you in particular care about at this juncture.
I'm sure some 80 year olds before us thought the same of us using that term.
This article is completely backwards. We do not want to manually manage what-gets-refreshed-when. The whole point of React was to react to state changes automatically.
> The whole point of React was to react to state changes automatically.
It isn't, given that React requires you to provide an array of dependencies when using useMemo and useEffect. The point of React is to automatically update the DOM when a virtual DOM tree gets modified.
Yeah, I'm interested to learn more about signals, but the article seems to miss the whole point of brute-force state updates -- less cognitive complexity.
I don't like the style of code in the article, with weird functions like "useState" and "useSignal". Looks ugly to me.
Also, it seems that with signals you must use immutable values only. Imagine if you have, let's say, a text document model, and you need to create a new copy every time the user types a letter. That's not going to work fast. And there will be no granular updates, because the signal only tracks the value (whole document), not its components (a single paragraph).
Also the article mentions rarely used preact and doesn't mention Vue. Vue can track mutable object graphs (for example, text document model). But Vue uses JS proxies that have lot of own issues (cannot access private fields, having to deal with mixing proxies and real values when adding them to a set, browser APIs break when a proxy is passed).
Also I don't like that React requires installing Node and compilation tools, this is a waste of time when making a quick prototype. Vue can be used without Node.
Immutable does not mean you have to copy the whole structure. You can store only the changes. This is how immutable data structures work in functional languages such as Haskell.
> Also I don't like that React requires installing Node and compilation tools, this is a waste of time when making a quick prototype. Vue can be used without Node.
You lose a lot though! You don't get minification and tree shaking, single file components, or hot module reloading. In practice, HMR outweighs the cost of setting up a Node/Deno/Bun environment.
> it seems that with signals you must use immutable values only. Imagine if you have, let's say, a text document model, and you need to create a new copy every time the user types a letter.
Too small. Imagine if you have a 2GB mutable file. Each keystroke in the middle of the file has to move the whole 2nd gigabyte backward.
> Imagine if you have, let's say, a text document model, and you need to create a new copy every time the user types a letter. That's not going to work fast. And there will be no granular updates, because the signal only tracks the value (whole document), not its components (a single paragraph).
Funnily enough, back when storage was slow enough that saving a text document involved a progress bar, one of the big advantages Word had over competitors was lightning fast saves, which they accomplished by switching to an immutable data structure. That is, while others would update and save the data, Word would leave it untouched and just append a patch, skipping lots of time spent rewriting things that an in-place edit would shift.
The “copy everything” mental model of immutable programming is really about as wrong as a “rewrite everything” mental model of mutable programming. If it happens it’s bad code or a degenerate case, not the way it’s supposed to happen or usually happens. Correctly anticipating performance requires getting into a lot more detail.
Preact signals are far superior to other state management patterns for react, but don't use a ContextProvider as shown is this article, pass the signals as props instead.
passing the value on and on as you go down a component chain. Context lets you avoid all that.
Where signals offer an important benefit is in localizing re-rendering. If you use context with regular, non-signal values the entire VDOM tree has to be re-rendered when the context value changes (because there's no way to know what code depends on its value). With signals you can change the value of a signal in the context without changing the context itself, meaning that the only part of the VDOM tree that gets re-rendered is the one using the signal.
With performance considerations out of the way context becomes a really interesting way to provide component composition without having to specify the same props over and over as you make your way down a chain.
ContextProvider is for when you have some data that any random component might need, and you don’t want to clutter up the system by passing it through every component (this is called “prop drilling”). Or maybe you can’t pass it through some container component that you don’t control.
That consideration is orthogonal to what the useful data is. It could be a signal, or not. In other words, signals are not an alternative to context.
It's hilarious that the Observable pattern that MVC and Qt are organized around has become "a game-changer for large applications where context is used to distribute state across many components" this year. MVC is maybe 50 years old now?
It remains a bit of a mystery to me that applications seem to grow further and further from traditional game techniques. Both in how state is propagated through the application, and in how it is represented.
Like, I understand why people aren't going full 3d game simulation style for applications. But I don't understand why things are as divergent as they are?
I can't say as I'm not familiar with Preact signals, but I do know the Angular team brought on the author of SolidJS to implement signals in Angular. Though I think I remember reading at some point that Preact signals were essentially directly ported from SolidJS, so they're likely similar if nothing else. (Someone correct me if I'm wrong)
My mind immediately jumped to the recent Chat Control drama after reading the title.
One way I frame such issues in my mind is that it's about who has control (and how much) over what is rendered and when on the screen I carry in my pocket. To some extent it is now Signal when I use the app. One day it might be my State instead.
sethaurus|4 months ago
It's a collaboration between multiple library maintainers, attempting to standardize and unify their shared change-tracking approach.
h4ch1|4 months ago
I wonder some years down the future, if there will be no need for JS frameworks since a lot of what they offer will be integrated into JS itself.
https://github.com/proposal-signals/signal-polyfill
barrell|4 months ago
In the time that I’ve been using ClojureScript, the whole react community has switched to hooks. I find it so baffling - requiring your entire data structure to be contained within your component lifecycle? The thousands of calls to individual “useState” to track the same number of state items? The fact that every function is closing over historical state unless you manually tell it to change every time the variable does — and then this last bit in combination with non-linear deep equality comparisons?
I recently have been in the process of switching phrasing.app from reagent atoms to preact/signals for performance reasons (and as part of a longer horizon move from react to preact) and I have to say it’s been fantastic. Maybe 50 lines of code to replicate reagent atoms with preact/signals, all the benefits, and much much faster.
Very happy that there is react-like library so devoted to first class support of signals.
yxhuvud|4 months ago
Oh boy. The youth of the author is really visible.
niam|4 months ago
I'm sure some 80 year olds before us thought the same of us using that term.
Aldipower|4 months ago
Traditional? I remember when React was the new kid on the block. I am getting old! :-D
sethaurus|4 months ago
zxspectrumk48|4 months ago
jjj123|4 months ago
By default, usestate causes unnecessary rerenders which signals avoid (all automatically).
afavour|4 months ago
It isn't, given that React requires you to provide an array of dependencies when using useMemo and useEffect. The point of React is to automatically update the DOM when a virtual DOM tree gets modified.
agos|4 months ago
ptak|4 months ago
codedokode|4 months ago
Also, it seems that with signals you must use immutable values only. Imagine if you have, let's say, a text document model, and you need to create a new copy every time the user types a letter. That's not going to work fast. And there will be no granular updates, because the signal only tracks the value (whole document), not its components (a single paragraph).
Also the article mentions rarely used preact and doesn't mention Vue. Vue can track mutable object graphs (for example, text document model). But Vue uses JS proxies that have lot of own issues (cannot access private fields, having to deal with mixing proxies and real values when adding them to a set, browser APIs break when a proxy is passed).
Also I don't like that React requires installing Node and compilation tools, this is a waste of time when making a quick prototype. Vue can be used without Node.
Jaxan|4 months ago
julenx|4 months ago
[1] https://react.dev/learn/installation#try-react
85392_school|4 months ago
mrkeen|4 months ago
Too small. Imagine if you have a 2GB mutable file. Each keystroke in the middle of the file has to move the whole 2nd gigabyte backward.
handsclean|4 months ago
Funnily enough, back when storage was slow enough that saving a text document involved a progress bar, one of the big advantages Word had over competitors was lightning fast saves, which they accomplished by switching to an immutable data structure. That is, while others would update and save the data, Word would leave it untouched and just append a patch, skipping lots of time spent rewriting things that an in-place edit would shift.
The “copy everything” mental model of immutable programming is really about as wrong as a “rewrite everything” mental model of mutable programming. If it happens it’s bad code or a degenerate case, not the way it’s supposed to happen or usually happens. Correctly anticipating performance requires getting into a lot more detail.
AlienRobot|4 months ago
pingoo101010|4 months ago
e.g:
afavour|4 months ago
Where signals offer an important benefit is in localizing re-rendering. If you use context with regular, non-signal values the entire VDOM tree has to be re-rendered when the context value changes (because there's no way to know what code depends on its value). With signals you can change the value of a signal in the context without changing the context itself, meaning that the only part of the VDOM tree that gets re-rendered is the one using the signal.
With performance considerations out of the way context becomes a really interesting way to provide component composition without having to specify the same props over and over as you make your way down a chain.
wrs|4 months ago
That consideration is orthogonal to what the useful data is. It could be a signal, or not. In other words, signals are not an alternative to context.
acjohnson55|4 months ago
kragen|4 months ago
rudedogg|4 months ago
taeric|4 months ago
Like, I understand why people aren't going full 3d game simulation style for applications. But I don't understand why things are as divergent as they are?
Is this just my off perspective?
GCUMstlyHarmls|4 months ago
Dagonfly|4 months ago
I feel like at some point we are gonna complete the cycle and have MVVM/MVC binding engines in frontend dev.
There is barely any difference left between createContext+useSignal vs. C# DataContext+ObservableProperty.
unknown|4 months ago
[deleted]
jzig|4 months ago
shoemakersteve|4 months ago
paweladamczuk|4 months ago
One way I frame such issues in my mind is that it's about who has control (and how much) over what is rendered and when on the screen I carry in my pocket. To some extent it is now Signal when I use the app. One day it might be my State instead.
hhthrowaway1230|4 months ago
rivetfasten|4 months ago
Compare: "import a specific lightweight library and wire together as needed" vs "write the whole app in terms of a bloated framework".
I've been out of the frontend game for a while, but what does react give you that knockout and maybe some url management logic do not?
I guess components are supposed to standardize modularity, so you can easily import some random widget?
prokopton|4 months ago
koakuma-chan|4 months ago