I don't really understand why people like signals again. I used a signals-like reactive programming model in VueJS a while ago and hated that you could never be sure exactly where things were being changed. Thankfully it seems that the React creators and maintainers are not hopping on the signals train and are instead adamant about unidirectional dataflow with explicit mapping of state to UI, which, as has been the reason for why React had been invented in the first place, makes reasoning about the application much easier [0][1].<p>This is a good thread about their drawbacks [2]. Apparently, both the below examples actually do different things:<p><pre><code> function One(props) {
const doubleCount = props.count * 2;
return <div>Count: {doubleCount}</div>
}
function Two(props) {
return <div>Count: {props.count * 2}</div>
}
</code></pre>
Like the tweeter says, signals are mutable state. I'll stick with unidirectional data flow in React.<p>[0] <a href="https://twitter.com/jordwalke/status/1629663133039214593" rel="nofollow">https://twitter.com/jordwalke/status/1629663133039214593</a><p>[1] <a href="https://twitter.com/dan_abramov/status/1629539600489119744" rel="nofollow">https://twitter.com/dan_abramov/status/1629539600489119744</a><p>[2] <a href="https://twitter.com/devongovett/status/1629540226589663233" rel="nofollow">https://twitter.com/devongovett/status/1629540226589663233</a>
At first I thought this was talking about Unix signals<p>Then I thought for a moment it was talking about a "signal" in the information theoretical sense<p>All I came away with was that they've invented a new name for event driven architectures and/or data flow programming.<p>I know naming is hard but we need to stop overloading terms.
signals represent continuous time varying quantities, like an electrical voltage, an audio signal or the current mouse coordinates. streams (event streams) represent a sequence of discrete events, like key presses or network packets or financial transactions.<p>the key difference is in backpressure strategy: signals are canonically lazy, they don’t compute or do work until sampled, and only the latest value is relevant (nobody cares where the mouse was a moment ago when nobody was looking). streams are eager, you can’t skip a keyboard event or a financial transaction, even if the pipes are backed up – instead you have to tell upstream to slow down so you can catch up. The benefit of event streams is the guarantee that you'll see every event, which means streams are suitable for driving sequences of side effects (keyboard event -> network request -> database transaction).<p>signals are a good fit for rendering because you only want to render at up to say 60fps (even if the mouse updates faster, which it does). and you only want to render what’s onscreen, and only when the tab is focused. rendering (say dom effects) is indeed effectful but not in the discrete way; the dom is a resource, it has a mount/unmount object lifecycle, and due to this symmetry it is a good fit for rendering whereas isolated effects (without a corresponding undo operation) are a terrible fit for signals because backpressure will drop events and corrupt the system state.<p>You can use streams for rendering too, but it's dis-optimal, and potentially by a <i>lot</i>. If your app chokes on a burst of events, you want to skip ahead and render the final state without bothering to render all the intermediate historical states. Signal laziness is what enables this "work skipping"; a stream would have to process each individual event in sequence.<p>I have no idea if JS projects get the backpressure right, can anyone confirm?
It’s kinda funny to see “signals” coming round into fashion or popular discussion in front-end tech Twitter. Mobx is a signals state management library has been around for 7 years. Notion used signals internally for state management and often when engineers joined they’d ask why we use signals over Redux, can we switch to Redux because it’s more modern, etc. Now it’s 4 years later and for some reason this pattern is all the rage. I’m glad I didn’t waste time on Redux just in time for trends to move on.<p>To discuss more specifically TLDraw’s Signia library, I think the ability to do manual diff tracking & incremental updates for computed stores is an interesting “escape hatch”. Docs here: <a href="https://signia.tldraw.dev/docs/incremental" rel="nofollow">https://signia.tldraw.dev/docs/incremental</a><p>Most signal libraries I’ve seen try to lean hard into magic auto-tracking of dependencies which means they make it really easy for the developer to correctly observe a lot of dependencies, cool on correctness, but then have a very limited set of tools to deal with the performance implication of some computation needing to re-run a whole bunch. The differential tracking here means that if you see such a hotspot, you can get really manual optimization of recomputation without needing to squeeze into the libraries pre-packaged observable collection API.<p>Downside of this API is it seems quite easy to get it wrong.<p>Another thing I like about Signia is the use of logical time. I saw this first in Jotai internals, then in Starbeam. I haven’t dug into the source of the library yet but I think logical time is a good approach and makes inspecting internals make a bit more sense than inspecting systems (like Notion’s) that rely purely on update notification listeners.
Building 'signal graphs' because views subscribe to err signals is an old hat for re-frame users who are benefiting from a clean and simple mechanism to react to data changes since forever.<p>Subscriptions grow from the leaf up to the root (which is a single app "db") and so computation is minimal. If something writes to the "db", only relevant subscriptions are recomputed and only views subscribing to those are "repainted".<p>Works like magic.
Hmmm... attempt to define signals using ReactJS' useState()/useMemo() vocabulary appears as really bad idea.<p>PReact's signal() as a concept is better - more pure. <a href="https://preactjs.com/guide/v10/signals/" rel="nofollow">https://preactjs.com/guide/v10/signals/</a>
I did some intense Linux/POSIX signals work in C over the last year, and expected this article to be about those creatures, since so foundational.<p>Nope.
This does not differ from the logic that comes with React hooks. "We've added new magic for you. Everything is done in the background. You just code the way we want.". This logic generally results in new complexities eventually. Because I don't think there's any benefit in trying to hide the obvious complexity in this way.
Remember when signals - aka the observer pattern - were a stupid overengineered enterprise design pattern object oriented programmers had to use because they were too dumb to understand functional programming?<p>Now they're back, baby. Happy to see them used again, even if we've had to razzle it up a bit with a new name.