LongCut logo

Designing Async-First Signals

By Ryan Carniato

Summary

Topics Covered

  • Async Signals Rethink Solid 2.0 Foundation
  • React API Design Masterful Despite Flaws
  • Signals Enforce UI Consistency Guarantees
  • Suspense Inverts Control for Layout Boundaries
  • Deferred Disposal Enables Zero-Cost Transitions

Full Transcript

All right. Hello and welcome to my stream today. Sorry, I'm running a

stream today. Sorry, I'm running a little bit late. Let's get that mic up.

All right. Check. Check. All right.

How's everyone doing today?

All right. All right.

I think uh the stream today might be a little bit quite a few controversial topics actually.

Um I'm curious where things go. Hoping

we getting close to solid 2.0 and and I mean you guys aren't going to love what I say in that regard because I was very very close to where we needed to be for solid 2.0 at least on the client side. I

was about ready to move it into like alpha stage and then I realized some things that needed caused me to rethink things about 3 weeks ago and that's kind

of where we are today. Um and yeah, there's some there's some controversial stuff. Um really honestly uh I don't

stuff. Um really honestly uh I don't think everyone is going to like what I have to say today. Um which is okay. Um,

it's kind of like when we talked about splitting effects, but I I want I think it's important that we talk about it because from my perspective,

what I'm talking about isn't really like we can always say that like this trade-off is not worth that trade-off.

But I think once we make certain assumptions or look down a certain path, there is a certain underlying physics to how things work. You know, like I often

say that we discover stuff, we don't invent it. That's what it feels like. Um

invent it. That's what it feels like. Um

here I think there's some truth underlying everything. So um maybe our

underlying everything. So um maybe our compasses are misaligned but um maybe we misinterpret what we see but

generally speaking we take scientific method and approach the stuff logically we will find that we often all come to similar conclusions um ultimately. So I

I I just want to put that out there. But

yes, I've been I've been working like crazy on stuff. Um, and I'm really excited to update everyone on what I've been talking uh, but what I've been talking about on the line a bit, what

I've been looking at. Um,

yeah. Hi everyone. How you doing?

I'm doing okay. Um,

I've uh definitely it it's been it's been a little while, you know, like at this point I've been like so far down R&D place. It's kind of funny when I go to

place. It's kind of funny when I go to like a conference like I was at JS Nation US uh uh last was it beginning of the week? Yeah. And I was like giving a

the week? Yeah. And I was like giving a talk on stuff that I've already like moved beyond a little bit. Um,

so it it is it's surreal when you're kind of like really like I feel almost detached when I like get really far down these R&D things.

But on the positive now, I feel like I know a bit more now. I've I feel like I've implemented like how many different reactive signal

systems and how many different um uh like concurrency models now? Like I've

done it at least three or four times. um

over the last 5 years. So like I feel like I'm I'm learning something each time.

Uh hi everyone all coming in. Let's go

Buzzy. Yeah.

[snorts] Um yeah, arguably that bad maybe.

Hey hello.

So, no, no, nothing like that. No, I I think we'll get into it. I made some notes for today so that that we can cover everything because there's a lot of

stuff. But I think something you have to

stuff. But I think something you have to understand about like the the the truth and the reality is I will sometimes give flack to react in terms of assumptions they make because their implementations

differ from the way that I view implementation. And I'm like, okay,

implementation. And I'm like, okay, well, we can actually tip the model on the head and we can get benefits you can't get other ways. This can change the trade-off slightly. But the one thing that I have a hard time faulting

React, and this is something very odd for people when they look at like alternative frameworks, is is their API design. I think React's API design is

design. I think React's API design is topnotch um in terms of like going, okay, this is the problem. How do I design something to fit the shape of the

problem? Right? I think every I think a

problem? Right? I think every I think a lot of times it's tempting to cut corners and I think a lot of times it's like we try and like get around things and it's funny because API is what

people interface with. So it's also the things that people um like dislike when they when they use React like why do I have to do this? Why do you make me do this? Why do you make me type these

this? Why do you make me type these extra characters? All like all this kind

extra characters? All like all this kind of stuff. And I mean sometimes a

of stuff. And I mean sometimes a framework author it's hard not to be like you know treat people who complain like that like little children you know

who are complaining that you're giving them their vegetables but like it's there there's usually a very good

reason for this and maybe that reason isn't completely understood but that that's not where we're going to start today. I just wanted we're just I'm just

today. I just wanted we're just I'm just calling shots and letting you guys know that um today's stream might be a little controversial placing signals with this update. I

mean, not really, but I think I think this upupdate is something worth talking about today as well. I Yeah, we're going to pull into stuff from Remix 3 from that perspective when we talk about

timing and examples that I'm going to talk about today. Um I think today's the day that we finally uh look at Joseph Anna's talk. um from React Comp because

Anna's talk. um from React Comp because it's actually it all relates and um [clears throat] in into this.

Yeah. I I I mean to be fair, the tpples that came back from from hooks was very like it was like what I was looking for. I think

the one challenging thing is like from my perspective it's so funny because like mo big frameworks like Vue and like um

yeah like Vue actually only one and Angular doesn't have really the equivalent like hooks was like from my perspective hooks were not the front of the they were like at the end of the

chain like other frameworks has had things that look like hooks way before reacted and not just like a couple like many. It's actually like they had those

many. It's actually like they had those and then kind of got rid of them because of React. So um but from my perspective

of React. So um but from my perspective the the tpple in React to get the read write segregation is like one of those like nuanced things that are just

masterful stroke even if like the hooks themselves are feel derivative even if they didn't really give them credit but like like generally the the the

tpple is just genius. Um, but it's a that is the exact kind of API nuance that that I'm that I talk about. So

that's fair.

Um, okay. Yeah. I mean, and and just just we're going to get to this in more detail as we go, but the idea here is um we want it's this is almost as core as

why signals are different from observables, right? We want to and I'm

observables, right? We want to and I'm going to use this opportunity right now to to to pull up pull up my X and some

other stuff in the background here. Um

it's it's that like RX is an event system essentially like there there are different versions of reactivity you know and you there's very thing but RX is generally an event

system. Um it's actually more similar to

system. Um it's actually more similar to remix 3 of all things funnily enough.

It's it's like you just feed these channels of events through and you make sure that like you get some eventual consistency that way. Um but that's the the the guarantee. They can be synchronous. They can be async or not.

synchronous. They can be async or not.

The the thing that makes signals special and reactive frameworks in general like React or that special like the reactivity is really an enforcement of a certain type of guarantees around

consistency. The idea is that

consistency. The idea is that you only you can only trust your UI if you believe it to be consistent.

Otherwise, you're going to have to like people won't trust it and they'll refresh the page. So you have you want to give the end user a sense of um trust

by being consistent by making sure that whatever they do looks consistent seems you know doesn't give them like oh is this really updated you know kind of

mentality and then secondly um developers also kind of fit into this that if they don't see that they might not trust their tools or their

frameworks. So like signals are about

frameworks. So like signals are about consistency. So when I talk about async

consistency. So when I talk about async often it's it's it's not like it's not about transformation but synchronization. And I think this even

synchronization. And I think this even with async inside signals themselves keeps this property alive where um my my idea here and this will be much later we

get to this is that signals um are this mechanism to provide synchronization guarantees. Um RX doesn't worry about RX

guarantees. Um RX doesn't worry about RX cares if something fails and you re retry it three times and do this and fork this. It's it's it's procedural.

fork this. It's it's it's procedural.

It's a process that you go through where signals are like it just is like it's like this is the rules of the universe.

At any time I look at it the you know I must be seeing something that I can trust and believe.

I don't know it's a good explanation.

It's the weirdest part about being where I am like deep down the rabbit hole.

No, as usual, this is stuff that I am literally inventing or discovering as I said much more thing uh apt description on the spot. So when some people when

they're they're looking at my content and stuff, they'll be like they'll be like, "Oh, where can I read up on this stuff?" And I do have some HackMDs that

stuff?" And I do have some HackMDs that I've been penciling out. But in terms of the scale of like where we are in terms of the process here, when I stream stuff, it is literally a week or two

since I've had the revelation myself.

that's within that first kind of gap time. When someone writes an article on

time. When someone writes an article on dev 2 or something consumable, you know, on Medium or whatever that minimum they probably been working on something for 2 or 3 months. Um, and

like, you know, it takes I take that content out and then it'll be like 6 months till the conference talk and then maybe like a year to the short to the point video. Like basically this is as

point video. Like basically this is as cutting edge, bleeding edge as it gets on this topic. um if you join the stream and I apologize. I my communication is not as refined as it could be because I

I'm literally researching this stuff right now. This is this is stuff that is

right now. This is this is stuff that is about as you know breaking news so to speak as it can be. Um I've been covering stuff incrementally through my streams for the last year, right? Last

February I did signals 2.0 future async and a lot of the fundamentals and foundations are there that I'm going to talk about today. But what I I I've had

some major revelations the last week, couple weeks, and I I want to kind of talk about what I think that means and what it inspired me to do.

Isn't that a description of immediate mode? I I don't

mode? I I don't I don't It doesn't have to be immediate mode, right? Like it's it's I mean

mode, right? Like it's it's I mean immediate mode for those who don't know immediate mode is like when you like rerender the whole page like when you like basically like game engines are

often that it's often easy to to like produce synchronization when you rebuild everything because then you know like there's nothing weird artifacts are going to creep in. You just kind of go

wipe it out. Fortunately not always very performant. Um, but the the the

performant. Um, but the the the mechanism that actually makes things stay in sync is I view it as a reactivity system. Whether it's the

reactivity system. Whether it's the harness around the immediate mode renderer or a very sophisticated synchronization system around a retained mode renderer like um retain mode is the

alternative. That's like the DOM. It's

alternative. That's like the DOM. It's

things that persist and you just like mutate or change parts of it. Um but the the approach here doesn't actually ma matter that much and it's actually very interesting because um you could say

that React has been approaching this from a immediate mode perspective while I've been approaching it from a retain mode perspective but generally to similar goals or results right and and

there's always the thing that's always funny is because of performance immediate mode rarely stays immediate mode like there's always like some kind of exception some kind of persisted thing like hooks themselves for example

in the component model in React like you you don't just blow everything away even in immediate mode um like even theoretical because performance will

always take you back um right I'm trying to think of like other examples like uh in game engines like um Vulcan uh my understanding I was I was talking to

this guy a while back at a conference and he was explaining to me how they were actually looking at techniques of re retaining parts of the render graph And it wasn't just throwing everything

away every time. Um, which is really interesting to me because I see parallels there between, you know, UI research. I mean, this is probably more

research. I mean, this is probably more relevant to people like work on the React side where they're looking at how to bring more performance into basically immediate mode rendering, but it's still

very interesting stuff. Anyways,

um, did I though did I ditch transitions?

That's That's the thing. We We'll talk about that. I I I I love getting you

about that. I I I I love getting you guys all warmed up on this.

Okay. So, let me pull up my notes here for a second so I can remember what I wanted to talk about. Okay.

Yeah, we we should actually start with um Yeah, I Yeah. Uh sorry, I love this.

Yeah, double buffering video games is basically beat on. Yeah, I mean Yeah. God, it takes me back. I sorry for

Yeah. God, it takes me back. I sorry for those of you who don't know, I got into programming because I want to make video games. Um, so it's kind of an

games. Um, so it's kind of an interesting thing because you think like and and you find this a lot a lot of the like like people who are really invested in in these realms especially in

graphics quite often um are immediate very functional [clears throat] programming immediate mode kind of people and I think that would have been my um my positioning you know arguably

but then I realized that the DOM isn't I I realized two things well first of all the DOM isn't immediate mode which meant that like trying to enforce my abstraction on top of it was never

going to be the like most optimal at least from my perspective. And the

second thing is I found something that I liked even better than video games. And

that was um it's so funny. It felt like a soduku or like a puzzle um digital circuit logic. And I actually went into

circuit logic. And I actually went into um computer engineering and and programming like like almost like old style arcade games with like circuit

boards rather than like a conventional programming language is the funnest thing that I I I don't know how else to put it. I just found it so incredibly

put it. I just found it so incredibly fun. Um the like I'm I'm a weird person

fun. Um the like I'm I'm a weird person who thinks like I I don't think verilog or VHDL is beautiful but I think that

the systems that work like that there's some kind of it feels very powerful or some kind of truth when when you describe things as like a state of being

rather than a grocery list. Um anyway,

okay. So

classic. He wanted to make videos in the front end. Yeah. Yeah. Well, I mean it

front end. Yeah. Yeah. Well, I mean it was video games or music. You see the guitars in the back, but I I you know I was those are things that probably

appeal to a certain type of young person into nerdy kind of stuff.

You know, go one way or the other. But

um yeah, then I end up in front end, which I mean wasn't unrelated. I I

started building websites to promote my band. So yeah. Okay. Sorry. Um,

band. So yeah. Okay. Sorry. Um,

why is my screen flickering so much? I'm

going to have to do something about my cable. It's not fine. At least it's not

cable. It's not fine. At least it's not impacting you guys. Okay. So, uh, where do I want to start? I I'm going to start by first just, um, sharing my entire

screen here for a moment, even though that's probably not going to be too relevant right now. Um,

but I feel like for me this journey starts by talking about async in UI frameworks

just in general, right? And yeah, sorry, I just wanted to get that in there.

Let's talk about that for a second.

JavaScript itself is a language that's very unique in that um [snorts] is single threaded right like essentially single threaded I know

there's there's exceptions you can make workers and all this but and it was basically designed to work in the browser um

and what's interesting to me is that the model like JavaScript started as something which It was a weird amalgamation of a bunch of stuff, you

know, like it had like um you know like functional programming pieces with like a sort of object-oriented inheritance like prototype typical inheritance and

something it's a weird language and the addition to of asynchronous features to it um you know didn't follow what a lot of other languages are doing at the time

as well. like instead of like you know

as well. like instead of like you know going okay let's make a new thread or something it was like no we'll just have a really powerful scheduler right and

which makes sense like with the browser you only have one user you're catering to so like while you want to be concurrent while you want to be able to have multiple things on the fly you don't actually necessarily need to be

parallel um that I mean that that's at least a logic to it and you could be like okay well that seems reasonable in the browser but then Rindall went and created node and

interestingly enough also took this model you know because it was using JavaScript and as it turns out I mean JavaScript is not actually the slowest uh language on the server it might not

be one of the faster ones but um the way that it could handle concurrency in terms of multiple requests because let's face it on a server a lot of times you are waiting on IO it's not like straight

processing it's like you know you're like okay request comes in this comes in you know then go fetch that data from a database. Well, while it's fetching from

database. Well, while it's fetching from the database, you don't need to be like saying like doing anything. You're just

like twiddling your thumb. So, like it can go, okay, you go back and do something else. So, JavaScript actually

something else. So, JavaScript actually built a fairly, you know, performant way of switching contexts really rapidly between the different things and a scheduler that supported that. Um,

obviously Ryan had to do some work himself early days to make sure that it could work on a server. There was a lot of things that weren't in the JavaScript spec. you know, you need stuff like set

spec. you know, you need stuff like set immediate and ways of like more control over that scheduling. But we've seen that in the browser over time, even after that, we we've started getting a lot of those kind of tools make their

way back out, you know, the concept of like microtask queuing and um you know, which came with promises and um you know, and whatnot like this basic work

towards a very comprehensive approach to scheduling. Um it's not like

scheduling. Um it's not like multi-threaded. It's not go routines.

multi-threaded. It's not go routines.

It's not like but it's something that's very built in and almost automatic. You don't have to

almost automatic. You don't have to think about it much. I mean you have to understand the timing because you know promises resolve at different times async wait you know stuff that got built on top over time. But generally speaking

you could just set a bunch of timers and your code will just kind of schedule in a reasonable way and that was it. you know, if you've ever used, you know, multi-threaded code and,

you know, thread locking and like, you know, I think everyone's done this when, you know, you go if you at least if you gone to college or whatever, you know, um what semaphors and like the whole like um

I it's been so long I can't even remember the terminology, but you you know what I'm what I mean where you like go through those like classic problems like uh like dinner table or whatever. I

I'm I'm butchering the names of these things now, but you there's a whole category and you have to remember part of this also for

me is my timing coming into this stuff um I went to college university whatever around 20 2001 2002 and that was right

around the time that they were first adding like uh multi-core processors to computers. So like it was a very hot

computers. So like it was a very hot topic this idea of like how can we properly parallelize workflows and interesting enough obviously stuff in graphics was fairly easy to parallelize and that's why they ramped up to even

more cores but there's a lot of processes that we weren't readily really easily able to see how to parallel parallelize right away and without going like way too crazy down this kind of

tangent the thing to know is that JavaScript actually does a fairly decent job of just handling the base cases in a way that is fairly simplistic.

but just kind of just works. Um it might not give you all the control mechanisms you find in other languages but it it is built with asynchrony in mind probably just from the basis of being you know

client server model in the first place like a lot of your resources are not going to be in the browser. Okay.

How you doing chat with me so far?

The soft basket case is marked. Uh

yeah. No, I I've seen some people make games of Solid, which is cool.

Yeah. There's a lot of talk about how it's not like a single scale here.

Yeah. Yeah. Talking about like how Yeah.

I mean, it's kind of like you cache the von nodes in a lot of uh or or find ways to make block nodes like in like in Berno's performance techniques. It's

it's not so black or white. It's at this point a lot of it comes down to mental model and a lot of cases people will argue that um and I think it's fair that the mini mode mental model is a lot

simpler. Um

simpler. Um but on the other hand, I feel it doesn't give you necessarily as much control and I like control uh if you noticed anything. Um but it is an interesting

anything. Um but it is an interesting thing. I I think I think classically if

thing. I I think I think classically if you if you like look at this like stepping all the way back you should probably think that like a lot of um innovation should happen on retain mode

first and then with better abstraction make its way to immediate mode like that should the process things which makes in a sense certain industries um like game

industries or even like graphics like maybe it's just cuz the complexity of UI is so hard that it was easier to actually um go immediate first and and then kind of work backwards is that like

that doesn't make a lot of sense in terms of like the engineering or the mechanics that need to happen behind the scenes. As I said, if you're if you're

scenes. As I said, if you're if you're finding ways to optimize and actually do more stuff like uh like sort of do less work, you you probably start with retain mode and then figure out better

abstractions on top of that. But we've

kind of been the other way around which as I said it feels sometimes crazy because like when you're working on the web and the DOM, it's retain mode. It's

like this thing that stays around. So

having like React being the most popular UI framework is kind of crazy. Like I I I people I don't think people appreciate how crazy that is. And I'm not saying this in a negative way. Like it props to

the to React. You know, it's it it's it's kind of bonkers in my mind that that kind of approach could be the like the most prominent one. I I think it's good to have alternatives, but the fact

that it's like so much more prominent the other ones seems like somebody dropped the ball. Um,

collectively maybe we dropped the ball like uh I I I could picture a world where React wasn't the most popular UI framework and I was a huge fan of it as

I said um you know like for doing something really interesting. Instead,

it's the 4ERunner, which is like, as I said, it just doesn't make sense from my my engineering brain standpoint.

How we doing, chat? You guys are talking faster than I can keep up with what we could hear.

You haven't missed anything.

Okay. So I I'm just I'm just establishing right now like JavaScript is a weird language. Okay. So

um I don't know how many frameworks actually took thought took much consideration into async early days.

That's all I'm trying to say. It's just

because like the JavaScript model kind of like handle it for you. It's like

okay well I will set a timeout or whatnot you know like. And I have to give a lot of credit here. Um, React

seemed to be one of the earliest frameworks that actually were like, hey, we're going to actually make mechanisms for this, right? Um, suspense comes to mind. Transitions come to mind. Um, and

mind. Transitions come to mind. Um, and

I was very very influenced by those.

They both got announced like 2018ish, I think, if we go back and look at it. Um,

maybe 2017 for suspense. There was a talk in React Comp Iceland and then like um, you know, yeah, I think it's the

Iceland talk. Anyways, the what what I'm

Iceland talk. Anyways, the what what I'm trying to get at is you get the sense that React for a long time has actually been thinking about

these problems. Um they as I said something we might not appreciate at first like early on I might have you know been like worried about like it's very easy when building frontend

libraries to kind of like focus on like how do I make sure my UI is fast and all my user interactions are buttery smooth so to speak and that is a synchronous

synchronization problem. Um, and I'm

synchronization problem. Um, and I'm like I'm going to call right now like there if you're looking at performance in that and like fine grain rendering signal, it's hard to beat that kind of

situation if that's your whole world.

But as I mentioned be before React started, you know, uh, fax.js back in the day. Did Did we ever pull that up? I

the day. Did Did we ever pull that up? I

can't remember. I I I I like fax.js.

Let's see if I can find it. Jordan Walk.

Yeah. Okay. Let's Let's just pull this up for fun. Um,

not that one. This one. I mean, this is 14 years ago. This is an old experimental project. Rack is much

experimental project. Rack is much better in every way and you should use that instead. But basically, he was just

that instead. But basically, he was just trying to like copy stuff from the server into the client. And this is kind of where the starting of the whole VDOM experiment started from because like I'm gathering we're talking about diffing

HTML strings in this thing. Um, they

didn't quite have JSX. there had you know like all the the some of the pieces are here you start understanding the

model this is probably not you know I'm just going to post it here just for fun but it it is interesting um nonetheless

so yeah I it's it's fine it it's a historical note, but what I'm getting at is sometime around 2015 16, React was

like, we're going to plan for the future. And async was part of that

future. And async was part of that future. And I think it's important to

future. And I think it's important to understand that because a lot of certain like decisions were made from that point on that people might not have been able to justify until the final picture kind

of started showing up, which literally took till about this year. Like I feel like it's been like 10 years, but like there was things they did that was controversial and we'll I think we're going to see as we go through the

meaning of it like why they made those decisions, but um we should fast forward a little bit,

right? Um are are many of you familiar

right? Um are are many of you familiar with with um with with these features at all? I I feel like if I if I just pull

all? I I feel like if I if I just pull up like I'm going have to pull up my stack blitz right now. Of course I'm not signed in on this computer. Watch it. I

won't be signed into GitHub GitHub either.

[sighs] It's been a while since I've streamed.

Sorry. Give me two seconds.

actually. Okay, we're in. Okay, we're

in. Um,

I'm just going to pick one of my random examples to just really basically show the kind of features I'm talking about.

Um, That's is it switching tabs?

Let's do where is it? Sorry. I've got so many solid to experiments tabs. This is

probably the one I'm looking for. Now,

this is a solid example. Um, solid 2.0 to be precise, but this was very inspired by React for me. um

source and very like you can kind of see some of these things in action. The idea is that there's a couple

I'm going to actually remove the transition here just for for sake here.

The first feature that was added is suspense. And at this point suspense is

suspense. And at this point suspense is available in a number of frameworks. Um

the idea is you have some app state or whatever some of it might be synchronous but the sometimes you have like this child

component which kind of fetches some data right um I'm going to use solid syntax here because I'm using solid but the idea here is you create I'm just making a delay but it's random but

essentially I'm just going to fetch some data when I go to this go to this page and essentially if if you don't have the data, how do you render the component? Right? There

there's this kind of thing, you know, problem. You can't render something

problem. You can't render something beforehand, but maybe you still want to render part of the part of the page. So,

when I refresh this page, what you're going to see very briefly is this loading indicator where you see the tab bar, but then the loading comes in. I

think everyone can kind of see this. And

um this is pretty standard um in a lot of frameworks. You have suspense in view.

frameworks. You have suspense in view.

You had I think an await component in spelt uh back in the day. Um we also have our suspense here. And I'm showing this loader. So basically there's some

this loader. So basically there's some semantical difference with solid because um suspense is a really cool technology because it inverts control um

essentially it says that unlike say a weight component um which is basically like don't show this until this promise resolves like you could you could picture you could do that with almost

any state right if you have a conditional like uh like um uh turnerary like show this data like if

data show this u UI. You could always basically just have some state and then go like fetch data and then set state and then continue like that kind of stop

pause um mechanism you know maybe fetch use a factor create a factor whatever was always possible to a certain degree

but what's interesting about suspense is it lets the children render basically offscreen which means it discovers it like the child isn't until we're down

here right So, we fetch this data below the suspense boundary. We don't know um that there's even going to be anything to fetch. If there isn't, we could

to fetch. If there isn't, we could probably just show the page right away.

But, but this is was a masterful stroke in the fact that it it was like conversion control. It's like look, I'm

conversion control. It's like look, I'm designing my layout in my UI. I want to know where, you know, this is where the loading importance. This is where the

loading importance. This is where the natural page boundary is. This is these are things that that make sense in terms of the design aspect of my page. And if

people add async later, this is where we fall back to. This way you can reduce like a bunch of intermediate states. We

were kind of in this problem early where it was like if everything was managing its own loading state, you'd kind of have like a dozen different spinners.

And this was like no, okay, look, I will handle the stuff that's not available.

You know, you can always nest suspense and make more of these states. But the

idea behind suspense is that you can kind of set a natural boundary. Like ch

child could be a lazy component that you don't have the code for yet too. It

could be something that fetch data. All

these aspects don't really matter to suspense. It just

suspense. It just puts a loading indicator till it's available.

Hey Mark, you you didn't miss very much.

I was just talking about about why JavaScript was a weird language. Yeah,

and you're right. I can put some of these experiments in as I as I go. This

one I I had to butcher a little bit because I had to remove this is this this exact example is actually if you go to saltjs.com and go to our tutorial

and again this is like way down I want to point out that async is like way down on the list we we get to an example um like the first example with suspense is

really easy it's just like hey get me a promise right and then it's like greeting and then What's greeting?

Oh, it's a laz it's a lazy component, right? Um, so I'm like faking lazy here

right? Um, so I'm like faking lazy here through the import and making a delay.

But and that's how actually React released in the first place too. They

they actually released it by a way of doing uh lazy code loading basically.

That way they can show something if the code isn't there. This code splitting makes it a lot, you know, more performant. You don't have to load all

performant. You don't have to load all the JavaScript for the whole application up front. You can do it a page at a

up front. You can do it a page at a time, you know. Um,

but the example that I want to get into is transition transitions. Um, which is this example exact example. I've been

making this forever essentially where you click on a tab, you update the tab, and then you have suspense wrapping it.

Right? So, I'm going to I'm going to this like we've had transitions. It's

funny. I I looked at React's work and we actually released a few of the features before them because I was like so into it once I saw that first Dan Abramoff uh demo. Not the I didn't care about the

demo. Not the I didn't care about the stupid radar thing. It wasn't about performance. People a lot of people

performance. People a lot of people dismiss this stuff because of performance like oh this is React's way of solving its own problems. No, no. I

was interested in this because it was immediately obvious to me how difficult it is to solve uh these concurrency problems in a consistent way which we're

going to get into detail on what I mean by that but yeah um this tutorial on the solid site is is an example of this example I it's it's the same it's the

same thing the reason I like the tutorial I share that one is because it actually has a before and after but the the key part about suspense is that um it just doesn't care. So when I go here,

guess what? Loading. Go back. Loading.

guess what? Loading. Go back. Loading.

Every time I switch, it just drops it out. And for situations like this, this

out. And for situations like this, this is pretty normal. You're kind of used to seeing this. And as I said, nested

seeing this. And as I said, nested suspense. What if I

suspense. What if I um put another suspense in here because I have this counter. And this counter is here for a very important technical reason that we'll get to a bit later.

But you notice this count is global. It

comes in through props count. So all

these components have the same counter on them essentially that goes through that's just getting driven from the app, right? And if anyone knows solid, it's

right? And if anyone knows solid, it's not a big deal. The the components don't rerun. So we're we just have a signal

rerun. So we're we just have a signal that's updating, you know, the RH3. But

what's interesting is what if we wanted to be able to show some of the content sooner than some of the other content.

So if you notice the my child component here typically is just you know fetch some data display it but then with uh

the child with suspense example I've wrapped an additional suspense wrapper around where we actually use that um fetched data so to speak. So it can

actually render more of the page before it hits it because suspense always goes back to the nearest fallback. So, what

I'm going to show here is like if I go here, loading, loading, but on this one, what you're going to see is the count the Yeah, let me go here. The count is still

there because I put the suspense boundary below. It doesn't trigger the

boundary below. It doesn't trigger the outer suspense. See, this one's just

outer suspense. See, this one's just loading. This one's loading um

loading. This one's loading um loading T. So, so to speak, right? So,

loading T. So, so to speak, right? So,

like or Trey, what am I saying?

Whatever. Am I French or Spanish today?

I don't know. Doesn't matter. Um, but

you see it's it's actually a different loading indicator. See the specific one.

loading indicator. See the specific one.

So this inversion is really really really powerful. It means that the

really powerful. It means that the application developer can decide where to put the loading indicators. It's not

about like component like I actually don't think suspense belongs in reusable components. Maybe people disagree with

components. Maybe people disagree with me, but like conceptually it's a way for the application developer to go like this is how I want to lay out my page and I want to make sure that um you know I can show stuff in a reasonable way,

put skeletons and it's do what I want and I don't care where the async is as long as it shows it in a consistent way. It it basically removes all the complexity around uh

coordinating these things. And it has a second really important use. It gives us a boundary for streaming. um you can basically go like look these are the blocks that we can hydrate synchronously

as they come in and you know we can basically stream and this was something that was very much on React's mind right from the beginning of introducing this API um Marco had something very similar

called async fragments um back in 2014 async fragments I I sometimes joke that Marco invented suspense back in 2014 um

but if you look at actually what what he's talking about in this classic article. He's talking about streaming,

article. He's talking about streaming, but it's a very similar idea like essentially he's showing like the sections of the page and then he gets here async fragment provider data search. Now, this doesn't have the

search. Now, this doesn't have the immerse of results. This is not a weight. This is literally, you know, um

weight. This is literally, you know, um the await tag, so to speak. So it's not quite the the same, but the idea that you can section up parts of your app

based mostly on like layout considerations. Like there's data

considerations. Like there's data loading considerations. You can't

loading considerations. You can't separate those things, but you like it isn't about what makes suspense so powerful here is it is it isn't necessarily about

just like awaiting this data, you know, so to speak, even though that's like effectively what it does. It's about a layout thing. It's there's a reason it's

layout thing. It's there's a reason it's a component. It's it's it's something

a component. It's it's it's something like a designer kind of thing like um I'm actually considering renaming this in the future in solid um just because I

think suspense is kind of like a doesn't convey that enough just just in a side note. I know it's become the kind of the

note. I know it's become the kind of the term but um as you see today we're going to change the behavior suspense enough that I don't think it's might not be suspense anymore. So, um, I think it's

suspense anymore. So, um, I think it's worth putting out there, but I I'm hoping you're kind of understanding how how we kind of get into async solutions here.

So um we've seen these examples. Now, the the challenge here, and I'm going to actually pull up one of my my talks because I talk about this stuff a lot.

And, uh, let me sorry, just going to grab my Beyond Signals talk that I just gave because there's a great slide in here. And

I'm kind of getting ahead of myself a little bit, but we're going to come back to this slide. When you're dealing with async, there's really I we've talked about this on stream. There's really

like four different scenarios you have to consider in terms of how you can handle things or you don't handle them and tear, which is kind of like the default. But what I

suspense is show the placeholder generally speaking. Um, and that's kind

generally speaking. Um, and that's kind of like the starting point. The problem

with the placeholder is not all experiences want like picture if there's some async on the page like you can cause this to refresh or parts of this to refresh you

know after the fact. It's kind of jarring that like you're doing stuff and then I mean I can make an example that does

that very easily. Um, and the reason is suspense is show placeholder, but it's basically bail out. It's like, look, the thing to

bail out. It's like, look, the thing to show is not ready, so we're just going to fall back up to wherever, you know, we know we're safe to show.

You know, it's consistent by the by the method of bailing out. But realistically

we have to consider that aspects of all four of these are actually important to us. Okay. So um there's other mechanisms

us. Okay. So um there's other mechanisms here. Um just to summarize even though I

here. Um just to summarize even though I want to get into the the the detail of it a bit more as we continue but show placeholder is basically suspense. Hold

in the past is a transition. It's

something um that we'll show. Show the

future is optimistic UI or optimistic updates. and don't pair um is what

updates. and don't pair um is what happens when you don't use these features. But I think one of the the

features. But I think one of the the biggest challenges is if you start opting into these features like suspense, how do you opt out of them?

Like if suspense is this whole boundary and you're like I don't I actually don't want to go to the fallback. I want to tear um classically for React this was

use deferred value and um solid we had something called latest um which lets us get out and lets us tear. But what I'm

getting at is all four of these are things that you need to consider when looking at an async um solution. Okay.

So, why are we talking about this today?

Cuz that's fine. Um you know, I I've shown

that's fine. Um you know, I I've shown this stuff before in stream. Um I'm

going to actually return the transition back in here. There we go. Transitions

back. And just to show you really quickly, it loads because it has no data. But now after the fact as we

data. But now after the fact as we switch, you can see that it doesn't actually remove it. It might gray out if it takes a while, but we're actually holding stuff in the past while we do

the next page. This is what a transition is. I'll explain in detail how this

is. I'll explain in detail how this works in a little bit. Um, we've

actually done a stream on this before, but um, what I wanted to kind of just highlight here is here's a feature that allows one of

those other modes. So I was pretty happy I actually implemented a solution for all of the above and that's why I started giving that talk because I literally solid has a solution for all

the above. It looks a lot like the react

the above. It looks a lot like the react solution unsurprisingly. There's some

solution unsurprisingly. There's some detailed differences because of the fine grain graph and stuff but generally speaking it, you know, these are the

same modes. I talked about stuff being

same modes. I talked about stuff being discovered. Um it makes sense that um we

discovered. Um it makes sense that um we would you know like even even if I could like think of slightly different ways to do stuff, we kind of end up at the same

place. You know what I mean? Like the I

place. You know what I mean? Like the I mean rename suspense component to placeholder component call transition hold like you know what

I mean? Like these things almost line up

I mean? Like these things almost line up one for one with concepts. you know, you just name the feature, right? And then

come up with the API that's suitable for the feature, right?

That that's a very Yeah. Yeah. Like a weight. Yeah. Yeah.

Yeah. Yeah. Like a weight. Yeah. Yeah.

Exactly. And spelt used to have a weight as well. So I think suspense is like

as well. So I think suspense is like really really powerful because the inversion of control like that it's read based. Um,

based. Um, yeah, looking at the code, we we talk about this high level because looking at the code of this stuff is freaking tricky.

Okay, so Oh, it's not it's not quite the same. Okay, fair enough. What people hit

same. Okay, fair enough. What people hit the same problems?

You use a way with suspense. Yeah. Yeah.

We're talking about Remix, too, because they basically needed a way to do streaming and React hadn't given them all the tools yet, so they started building stuff like halfway through.

Yeah. I mean, transition is a hard one.

The problem is I was calling them transactions for a while, but they're not actually transactions. Transactions

um suggest a discrete like action within time and the cancelable and roll back.

and maybe somebody when they these become parallel could. But what this actually is is a gradual progression to an eventual future. Um we'll talk about

exactly what transitions are in a little bit. Um Angular's defer to my

bit. Um Angular's defer to my understanding has a lot of similarities like I know the use under like specifically like lazy.

I I feel like the fur is a bit if you took like an await and like lazy um from React uh sort of like took an await which is kind of like suspense and lazy

and just kind of jam it together in the same thing and then you're like this block is something that's lazy and does that I I the interesting thing is we've kind of split these into two

different concepts at least on the React side is that like um there's both the bounds in which you want the UI to care about it like in terms of a design standpoint which suspenses and then

there's like the me mechanism for signaling off a block to be loaded later or to be hydrated later which is what lazy does. Um

lazy does. Um yeah it's just it's Yeah. Yeah. It's

lazy. It's lazy loading components.

Exactly. Yeah. Exactly.

Yeah, the fur could be general on both laz loading data fetching, but they haven't said anything yet. I mean, it's fine.

Mostly it's for incremental hydration, which is fine. I mean, that was something I was always tempted to add, like add like an option to lazy to do incremental hydration. I just

incremental hydration. I just incremental hydration is challenging and I think it's a whole other topic. I

think I haven't figured out how to make it safe cuz the problem is sh state is shared and if state can change outside you can't hydrate it again like that it no longer

matches I I I don't actually know 100% what angular is doing there they probably should look at it maybe they because they can use signals they can go like okay I'm I'm going to wake it up anyways like kind of like quick does

like basically they just void that because you know I think that's a direction they're going at least because like whiz and quick need to do similar stuff.

Yeah. So, it's it's it's it's a little bit it's it's the same problem I have with like islands. Like it's it's very easy with islands if you have them

communicating to each other for them to basically do some client ups. they which

allows them not to hydrate anymore which is the reason that re react server components hydrate eagerly if possible and after the fact only render on the

client like not the server components but the use client like it can do SSR initially but after the fact you can't there all bets are off you have to run them on the client because some shared

state might have been updated and you can't trust the server anymore the server doesn't have the information unless you want to freaking serialize the whole thing and then we're back to

ASP.NET And trust me, ASPnet.NET is not where anyone wants to be. Um, okay. So,

see, it's so easy to get kind of tangented in here, but I just wanted to kind of like highlight it seemed pretty straightforward because from conceptual thing, we had this and then, do you know

what happened?

Spelt happened.

I mean, the same week that I went and did my stream, uh, maybe it's because I did the stream and Dominic Ganaway comes like knocking on the Discord and it's like, I want to I want to I want to show

you something we've been working on. You

know, this is while he was still working on the ST team and he's like, I think we figured out the model for async.

And he's like, I don't we don't want people to worry about like suspense and to worry about um you know transi transitions. Like we obviously we need

transitions. Like we obviously we need something like suspense, but we don't want people to like worry about like the the rip away feeling. I'm like I agree too. We made a model that doesn't rip

too. We made a model that doesn't rip away either. And he's like, "No, no, no,

away either. And he's like, "No, no, no, but like this will never rip away and there's no transitions and you just do the thing." And let me see if I can pull

the thing." And let me see if I can pull up an an example to kind of show what I'm talking about. Um,

let me grab one off X. I think I had some. Uh,

some. Uh, I think Rich Harris's original example is probably the best one here.

Uh, async Holding. Yeah, let's let's pull up

async Holding. Yeah, let's let's pull up this example from I talked to Dom Dominic was yeah he was a little bit frustrated at the time because he thought he had this really

cool model and they weren't like the rest of the team wasn't sold on it. He

said over time that they basically ended up to where he wanted it to be. He he

said it just took a little bit of time.

So I cuz I I asked him this the other day cuz I thought that too when I saw this model come out. I was like, "Okay, maybe this isn't what Dominic was like after, but he's like, it's basically got

to where I I wanted it to be." So um well this example um

I I I don't have a solid version right now but the classic example of this and this is felt syntax you have to take a moment to get used to it with the new

stuff but essentially you have state and then you have derived um async uh computed or memos depending on it like

the derived values And essentially there's a counter and then we await a multiply which is just faked out to be async based on it's like half a second

um up to half a second but essentially it's just calculating this function and and each one just gets inserted in the DOM.

>> [snorts] >> If you had a naive pairing approach, I mean, we can probably just build this

example in the solid playground really quickly. Um,

quickly. Um, I kind of want to do the old solid 2.0.

I I I think most people I'm I I don't have it right now. um to

be fair uh pre-built and I probably should have but when you look at this code where you're just like clicking a

number doing some async stuff and that's it. Um for the most part

it. Um for the most part I actually added this part into this demo. Rich's demo originally didn't have

demo. Rich's demo originally didn't have this. Um we can delete it for a second.

this. Um we can delete it for a second.

Rich's demo was like this. And you'd

click the button and it wouldn't update right away. It

wouldn't update until even though these are random, um it wouldn't update until all of these kind of came in, right?

Whereas like if if you see this demo, I feel like actually, you know what? Maybe

I should just remake it like really quickly. I I I think it's really

quickly. I I I think it's really illustrative.

Um, the best way to do it though, the best way to do it is take, actually, the best way to do it is

take one of my previous um, ex solid um, 2.0 examples um, that I did on the playground, which

means I might have to go back a little bit. Um,

bit. Um, it's funny. I've probably posted

it's funny. I've probably posted something very similar to this before on Blue Sky. I'm just not going to find it

Blue Sky. I'm just not going to find it right now, unfortunately.

Um, yeah, I'd have to go digging through Discord. This is so frustrating. I don't

Discord. This is so frustrating. I don't

feel like doing it right now. It's This

is too much of a tangent. The the thing is it's hard to show in a system that that protects against it, but the the naive approach

I can just do it in solid 1.0. It's not

going to be as satisfying, but it's fine because I don't have create async. So,

let's let's let's do let's just drop the spell code in here for a second and look at how we translate this. I don't feel like doing it in a stack blitz.

All right. So, we're going to go function down here. Okay.

down here. Okay.

Never mind. Let's do this.

Put this in a fragment.

I'm using solid, but conceptually this would be the same in pretty much any framework historically. If I just take this,

historically. If I just take this, put it this here format. No, too much stuff going on.

format. No, too much stuff going on.

Okay. So then what else do we want here?

N is going to be a signal.

So we're going to make these all into signals. Can I do

signals. Can I do command D, please?

Okay, missed one. It's fine.

missed one. It's fine.

And these are going to be all signal.

And then this will be set n + one.

And then this is going to be n set n.

I could probably just have used the increment function, right? Doesn't

matter. And then we need to create the rest of the graph. We're going to keep this function out here.

And then we need to make the rest of the graph which Can I format this yet? Yeah, thank you.

And then these are going to be in solid today. It's been a while since I used those. Going to be create resource.

And then just trying to think what each one looks like. It's going to be like create

like. It's going to be like create resource.

It's going to be based on n and then it's going to be multiply and

one example right that and then all right I need to actually the value in.

All right. And we need to do that multiple times.

A B C D E

and then uh what am I doing wrong here?

Two three four, five. There's going to be

four, five. There's going to be something that I'm missing.

It's funny. There's like object object on the end of it, but like it looks like it's doing what I wanted it to do. I

just don't I'm trying to think of what the object object is on the end. Am I

there's something that I'm just because I doubt Oh, right. Create resource is a tpple,

Oh, right. Create resource is a tpple, isn't it?

My bad.

I've been so used to using create async.

It's so nice.

All right. Yay. Okay. Sweet. I remade

the demo now.

Yeah, I'm going to create async. Okay,

my point is look what happens when I click this.

They all kind of just like flicker in as they feel like it all over the place. If

I click it like three or four times, it's just kind of like oo. And you could picture if I mean this is guarded because resource has cancellation but you could picture like in a lot of

solutions if you're doing this naively like even sometimes like if requests take different periods of time like later ones might come first and like is this the UI you want? Whereas you

know solid example if I click it multiple times I mean it does jumble a bit. So, I I mean, I'm not completely

bit. So, I I mean, I'm not completely happy with that, but generally speaking, I click it once, it it kind of ties this all together in

a in a more consistent way. And it and the important part that you have to understand here is I click this, it doesn't change the 18

right away. Even though

right away. Even though even though I uh I'm incrementing it, like if you look at the solid example here, when I click it, it's 33 right

away. Like we can we let's let's make

away. Like we can we let's let's make the the base longer. Let's go like look this has to be plus 200 at least, right?

If I do that, look what happens.

It up this updates right away. But this,

you know, whenever. Whereas if I do the same thing over here and go plus 200 on this on this new spell version,

it doesn't do it until everything's finished. So it's a bit like a

finished. So it's a bit like a transition except there's there's no transitions here. And I was like my

transitions here. And I was like my first thought was like this is kind of confusing because there's no abortance.

You you think your UI is just slow. Like

why is your why is this taking forever?

Right? like you click it and then it's like oh there it is right I was worried I mean the truth is when you have transition you get a pending state back

and and spelt actually um does they have this effect pending it's kind of like a global and then this way you can kind of see right away dot dot dot and then goes in so that easy

solve I just wanted to kind of show that I I saw this model and it's interesting because it kind of looked like transitions but Um,

it wasn't. But the this isn't the hard

it wasn't. But the this isn't the hard part about um like transitions. The hard

part about transitions is actually loading things off screen and not releasing what's on screen. That's

actually the hard part. Like when we had our example here, like how is it that when I move over here, I I still have

the counter counting up like still reactive while it's literally loading stuff on this other page. Like the if if you look at this from like a pure

conceptual standpoint, there's a decision here. And usually when you

decision here. And usually when you switch from one like in a reactive system with ownership if you switch from one one place to the other place you have to dispose of the old stuff right.

Um so even if we do some fancy stuff you know it's like not enough.

It is kind of like promise all but the important part is the consistency here right you don't like this is

tearing this is all 1.0 know that I'm showing here, but this this is tearing. Like

this like you've seen this before.

Sometimes tearing is okay, but I it's there were some studies that went into like trust. We were talking about trust,

like trust. We were talking about trust, right? What if a classic example um do

right? What if a classic example um do is the movies app still up? Um

movies app. Uh

solid movies app, but I don't want the solid one. I want the

solid one. I want the Who made it?

Taste taste js was it movies app I'm only going to be able to do this once but the angular example had tearing

and I started using this as an example of tearing because as you click like look at popular here you look at popular movies right if I go to action

some of them are the same so it didn't matter but it's going show action before or adventure here before it actually updates the movies. We'll be looking at adventure and then it'll the movies come in later. This is a classic example of

in later. This is a classic example of tearing. Now, you might say that this

tearing. Now, you might say that this example is fine, but there's other places where like you don't want to tear. You'd rather show the correct

tear. You'd rather show the correct header with the correct content.

Um, you could argue that this is better than having a placeholder like like you know it could have been this scenario, right? Where if I remove the transition

right? Where if I remove the transition again, how do I remove the transition?

Yeah, remove the transition. It's better

than like every time we move. Sorry.

Yinking it out from under ourselves, right? Like you've seen apps like that.

right? Like you've seen apps like that.

you know, me switching to animation didn't yank it out. It just showed the old stuff a bit

out. It just showed the old stuff a bit longer. So, like this could be an

longer. So, like this could be an intentional design um thing. But like if I look at the uh like say the solid one and the the view one, what you'll see is

as we change categories here, we show a loading loading indicator and we we actually delay

switching until like the whole content is available. You can decide whether that's better or not. The

browser does this a bit internally called paintolding. But this is this is

called paintolding. But this is this is like um an example of like transitions. Um this

isn't this funny example because this is actually like our server component example um that never got released. But

um I think Nux does the same thing. When

I go here Yeah.

Yeah. These these are not full page navigations even though they look like that intentionally so because they they use a form of of basically holding um anyway. Um

anyway. Um well exactly what this is the question that people ask like what if what if we we do something a little bit more extreme like

make this you know let's make this 3 seconds.

Okay, here we go.

Okay, we're in. Right. That was actually really long, longer than 3 seconds. But

now when I click on it, what saved us is that dot dot dot the the pending indicator. Pending

indicator like gives us an idea of what's going on. If I didn't have a pending indicator and I just just did this.

I wonder if Okay, that just seemed longer than three seconds. You're you're

you're like, "Did I get it?" You're like clicking. You're like, "Wait, did it

clicking. You're like, "Wait, did it work? Click it again. Did it work? Click

work? Click it again. Did it work? Click

it again." And then next thing you know, what?

So like you need the pending indicators, which is hardware hard to default to holding.

These are all reasons that I wasn't so sure about this as a default. Right.

Right. I I Let's pick this apart here.

It's longer than 3 seconds is blocking.

Yeah. Yeah. Like the spelled actually can do that tab demo with this model which confused the hell out of me because I kind of understood what they're doing. They're just locking up

they're doing. They're just locking up the the reactivity. How the hell could they keep the counter counting? Right?

This was something that that confused me and I and I realized only recently how they did it is that you you need

Selt actually had uh had a async felt um uh GitHub discussion back in April and

here let's take a look here.

I think I get quoted in here. Ryan,

according to Ryan in a stream, this is unsolvable issue without explicit dependencies. Okay. How do effects not

dependencies. Okay. How do effects not run until all async drives are updated?

Right? Like how do they do this smart stuff? And and Rich's answer is

stuff? And and Rich's answer is hilarious. Uh we don't run them. I

hilarious. Uh we don't run them. I

haven't seen the stream, so I'm not sure why it should be impossible. Well, it's

impossible from a uh from a discovery standpoint. You don't know what you

standpoint. You don't know what you depend on until you actually run it once, which is why I've been big on splitting effects because then you you can and it's the advantage of like

React's model with a separate dependency rate, right? Like if they get rid of the

rate, right? Like if they get rid of the dependency arrays in React, they're just compiling them in essentially. They're

not removing them. Do you do you understand what I'm saying? Um they

still happen before. Like there's two different phases. React renders your

different phases. React renders your component and then it runs your effects after. So when it runs renders your

after. So when it runs renders your component, it actually knows what the dependencies are because you told it compiled dependencies have a whole bunch of shortcomings. Um, as we know, like

of shortcomings. Um, as we know, like what if they use functions? What if the stuff's out of scope? Of course, React answer that is memorize the function itself, which I think once you're down that path, you're like cuckoo cocoa

puffs, so to speak. But, you know, if the compiler does it for you and you don't have to worry about it, maybe that's okay. Um my point is that like

that's okay. Um my point is that like like they know the dependencies up front.

How does spelt know? Well, its compiler does it. They basically look at the

does it. They basically look at the block. They look at it within local

block. They look at it within local scope and they actually associate it with like some kind of block concept whether it's a DOM or whatever you want to think about it but it's it's goes beyond the reactive system and they use

it to really smart effect because they identify these zones almost like from the UI framework from the component level and they were like okay this is a zone that we can associate and schedule these things with they don't have to

rely purely on runtime reactivities. So

I understand his confusion cuz he's like we just don't run them because they're already collecting them in a place outside of the reactive system like they're already like in sense we had our queue but like the work that I've done

on solid has been pretend nothing in the universe exists except signals. This

solution requires a compiler. it

requires a different scope context like it it requires some frameworky stuff to work but once you have it it's kind of like an obvious answer you like just

don't run them right but it it's important to kind of understand this distinction which is why I'm bringing out this thing what I've been trying to say

this whole time is different afordances are good at different for different use cases.

The thing is routing resolving can is a perfect example of where these async features come into play because you have pages that you're looking at pages in the

future, pages that require data, asynchronicity. This is one of the key

asynchronicity. This is one of the key places solid, you've been using trans, if you're a solid user, you've been using transitions for 5 years. They've

been just baked into the router.

you the only like is pending indicator was is routing that comes out of the router. You guys just maybe didn't

router. You guys just maybe didn't realize it. Some of you did. I get

realize it. Some of you did. I get

issues every week. Do you want do you want to see? I I bet you there's one right now. Solid router. I try and put

right now. Solid router. I try and put it in the read me. Try and put in the docs. Let me let me look it here.

docs. Let me let me look it here.

The first screen falls not working with anchor. Create as defer page refresh but

anchor. Create as defer page refresh but does not work with solids routers anchor. When clicking anchor, the entire

anchor. When clicking anchor, the entire page holds until the call completes.

This is a bug. It's not. But

essentially, this confuses the freaking hell out of people on a weekly basis. I still think it's the right default. I was okay with this. I built it into the design system,

this. I built it into the design system, but I have some experience now seeing what the results of actually building this stuff is. And we've been using doing this for years.

I mean suspense is kind of like a promise all but it's a non-blocking promise all know the problem with promise all is whatever point that you put the promise all you go await you're kind of like stuck

suspense lets you collect all the stuff independently and then figure out how to kind of filter down obviously when you're like boolean show don't show doesn't make a big difference but I

think I think it's important to understand that the non-blocking nature which is important for solid which renders once you you'll see like if I console log inside stuff that has suspension you're not going to see like

the stuff that renders off screen we keep when we insert it back into the page so like our ability to act like our ability to

actually um uh how should I put it like our ability to be non-blocking behind the scenes is actually to our benefit obviously if you

have cascading fetches blocking is bad because if you await and then you have you fetch again, guess what? Waterfall. But more so um

what? Waterfall. But more so um like you could you literally could render the whole shell of the stuff like and not repeat that work ahead of time and what else are you doing? Twiddling

your thumbs waiting for async worked.

You know it's the classic JavaScript problem. So um

problem. So um it's a little bit more complicated than promise all it. It's the same reason why you don't put a weight in client side components because different state updates can happen. You don't want to

like block. This is a fluid zone like

like block. This is a fluid zone like async components can make sense in something like server rendering which runs once. You know, generators actually

runs once. You know, generators actually make a lot of sense if you think about the way like streaming works, but generally speaking, async components make no sense. Like there's too many

different sources. You don't want to get

different sources. You don't want to get it all entangled in the same thing right?

Yeah, looking at query clients is really really quite like SWR or React query is really useful for understanding the mentality here. When I showed Tanner the

mentality here. When I showed Tanner the stuff that I'm trying to show today, he was just like he's like it's like he he got the primitives right away because he already had designed them himself when

building query. Again, this is

building query. Again, this is science discover, you know, but as I said, every so often someone surprises you like spelt did, which really sent me

kind of off like they've had this for months. I didn't really care much,

months. I didn't really care much, honestly, though. And we should talk

honestly, though. And we should talk about why my perspective changed here.

I mean, suspense used to have a timeout, you know. Uh, the truth is, I mean, yes,

you know. Uh, the truth is, I mean, yes, you could do something like that. It's

it's fine. And it's just you kind of never want to go back if possible. I I I think obviously the affordances might not be strong enough, but as long as you give people the tools for affordances, I

think it's okay.

Feels like state machines I mean state machine are a great solution to to managing lots of states. State machines

are like a very way of I think you know I call it the grocery list shopping you know like when you have a bunch of procedures and you're like look I need to categorize these procedures and understand what the state should look

like at the end of each one state machines give you a very descriptive way of writing that which is fine I just think they are verbose for simpler problems when you're like

I'm just freaking updating some UI now we could say that everything is a state machine you know you can metaphysical and we can go out there and it's true.

I'm just saying like kind of like RxJS.

It's it's one of those zones that you know when you need it, do you know what I mean? Like you will get to that point, but not every problem gets to that point. And it's funny, they solve

that point. And it's funny, they solve very different types of problems. State machines are really good um you know like RxJS and events are very good at solving a lot of transformational stuff

over time and state machines are very good for um reeling in all the random um the random like state. The problem is

we're we're creating too much state in the first place. like if if we actually looked at state in a different way and I actually had like a Twitter post about

this but um I mean where was it? Um

I was saying that it was it was one of my use effect rants. I can't remember if it was after my last stream or not.

[clears throat] H um yeah because that's isomeorphic first which we talked about with Tanner

yeah here besides being the perfect use of the mean I know a lot of comments playing the firmware sometimes shift the solution foration is less obvious in synchronization but that doesn't mean synchronization shouldn't exist we should all

derive more um damn it why can't I find it there should the um it doesn't matter. Um my point is

that it's it's too many. I know it's like right around here. It's I I basically blame use state for the problem with effects.

Yeah, I'm just like not finding it right now. Why am I so bad at this?

now. Why am I so bad at this?

It's been too long since I streamed. I

think that's the gist of the problem here. It's I'm probably like scrolling

here. It's I'm probably like scrolling right past it.

Oh yeah, here it is. It's like literally the next stream. People give People give use effect a bad rap.

Let me drop this in here. People give

use effect a bad rap, but it isn't usually the source of the problem. The

real problem is too many use states. It

does be able to see how the data is connected and model it too discreetly.

As those connections appear, it's easier to synchronize and refactor because basically instead of like changing how these things connect, you're just like, "Okay, I'll just like call a set statement in effect." And once you start down the path becomes harder to refactor because you can no longer see what the

the dependencies are. So because you wrote this one and then you wrote this one and kind of it just cascades out.

You can't look at data declarations be like oh it depends on this. You will

have to find all the places you write to it and and those locations depend on what writes to those. And this isn't react only problem. Some tools are better encouraged derived state but none are immune. Yeah. And what I was getting

are immune. Yeah. And what I was getting at is state machines are like when you have too much state. If you remember on the remix three 3 stream, I'm like I said something along like it uh the

lines of like remix 3 and um um uh xate were going to be best friends.

And the reason for this is because I think their pattern even though it removes um stuff that shouldn't be state from a React standpoint like it removes like temporary calculations because

they're based on events. I think the pattern still because it's not based on derivation actually creates more state than you actually want um because it

because you start writing to it from all the locations rather than deriving it and for that simple reason you will accumulate more state quicker and um x8

will look very nice to you um it doesn't matter if it's user effect or not it's the problem is not driving it's that's the problem here the core problem it's

not the It's not that uh that you're using use effect anyway.

Yeah, I like this. You know there's not another you can easily opt out by two separate states. one for the counter,

separate states. one for the counter, one for the drive. Yes.

So, yeah, the I'm actually not criticizing Six. It spelt was actually

criticizing Six. It spelt was actually incredibly like illuminating. The thing

is I just the behavior was not what I liked and the way they solved it was one that just wasn't interesting to me because it literally relied on a compiler and it was I was just like, okay, whatever. And thirdly, there's

okay, whatever. And thirdly, there's actually a third reason. I looked at this stuff and I was like, you know, when I want to transition, I'll, you know, put in a router or something or like a specific use case like an action,

you know, I'll wrap it in our action query helper, who cares? And then

unfortunately or fortunately, depending on how you look, I had Ricky uh Hanelon on on stream and he convinced me that

spelt was right, which is a funny thing. he probably

didn't realize he did. Um, like all those critiques aside, I had Ricky come on and first of all, we all know how hard

transitions are, but having now watched or and worked through the stuff on stream, having watched the React Comp

talks, talks plural and and learn with Jason, I was Like this is so hard.

It's the kind of thing that like I find myself making mistakes on like forgetting to call the second star transition. Like I I I've done this on

transition. Like I I I've done this on stream. I I've done this like Ricky's

stream. I I've done this like Ricky's done it. We we've all done it. And

done it. We we've all done it. And

trying to explain people what a transition is. I do it on stream so you

transition is. I do it on stream so you guys are educated. But at a certain point you're just like spelt doesn't freaking tell you what a transition is.

It just kind of works. Um

um maybe not exactly the way I I I want it to work, but close. And

the the final breaking point for me was actually Let me go back here. Okay.

Let's bring back this. Okay. Yeah. So,

we're in a good place. We're back to where we started. Okay. Let's go to the dashboard. Um

dashboard. Um it's it's funny how we we pull away different stuff from the same examples.

Where is it? React 19 async.

Me and Rick made uh made it to-dos app on stream and I was I I was kind of baiting it a bit cuz I I came up with this way to basically

take the client app in solid and not change it very much to um to make it async. Um, I I basically had

just wrapped the the the stuff in the actions in a transition, kept the same state updates for optimistic and everything just worked beautifully. Um,

obviously it was a little more verbose cuz we had to figure out how to continue. So I was like using generators

continue. So I was like using generators like with yield. I showed this actually on my talk. Um,

uh, let me actually get that in here too. Why not? I'll show you like uh

too. Why not? I'll show you like uh collection yan signals talk. Uh so sync to async complete. I'm going to drop this in the

complete. I'm going to drop this in the chat first. Let me go to source main. No

chat first. Let me go to source main. No

here.

Let's just drop this in the chat.

So okay I I was proud of this example originally because I literally just took the same client side code. Like if you're just building the to-do app, you just like

remove to-do, you just call this toggle, you just call this and just wrapped it in a transition and then did the server action and refreshed the data. Like I

was like, "Look, without touching any of the other code, this just works." That

was what I was like hoping to show like and I was like pretty proud of myself.

This has been something I've been working on a lot with with solid like server functions. We came up with server

server functions. We came up with server functions cuz we didn't want you to change your code like change your client side mentality.

like that was the whole design like back in I originally had proxies in 2021 when I was first working on this kind of like automatic RPC thing and then by early

2022 Nquille came in was like let's use the compiler right um but that that that is basically why we kind of came up with server functions and

it I wanted to slot them into tansty I wanted to slot them into any existing library that existed and I felt I was doing the same thing here Um, except I

mean generator. Who here knows what a

mean generator. Who here knows what a generator is? I mean maybe people in

generator is? I mean maybe people in this stream but like and the problem is if you do an async function then you have the stupid resume thing or like because we wanted to connect them or you

have to call start transition again you know like it just it is not nice. Um

I know that Ricky knows that I built it at the router for that reason. But

what Ricky did I did not see coming was he he he knows people didn't want to call a transition themselves. So he's

like what if you build transitions into the data fetching which is like what we do if you look at solid router and our action query things the there's transitions in there and he's like what

if the the trigger is built into the event handler in the base component. So

what he ended up doing in our example as we built it is at the top of the page where we have our stuff. Yeah, we have an add to-do action where we just await and refresh remove. I mean this looks

like simple easy to follow code. And

then if we if we trace this down to find where we call that our to-do input has an add action has an add to-do action.

And if I follow that down, we'll see that in here we start our our transition right?

And similarly um if we go into each of these to-do list we have a toggle action remove

action and we even um I'll go into to-do even further. Here we go. Toggle remove

even further. Here we go. Toggle remove

action and we we we handle our optimistic state here locally as we needed and we manage the transition with it. So,

it. So, what's cool about this is if these components already exist, the developer

um has pretty easy APIs to work with, right? They just await the thing. It

right? They just await the thing. It

seems pretty straightforward, but we started playing and composing and we we used Ryan Florence's select demo as the

basis of this. Um, for those who have not seen this demo, um, it's it's just a

cascading drop down. It's the silliest thing ever, to be fair. Um, but we we're like

it it's funny how many things just keep on coming back to the stupid example.

It's not stupid, it's a great example.

It's just it's there it is.

just to kind of show you this example.

Um, oh, this is I I made a new version that added an extra level to it. Okay, the

the original demo didn't have a country selector, but it basically worked like this right?

And as you change the states, it would reload the cities and auto select the cities essentially and show the loading state and handle this. And this is like

surprisingly interesting problem because the state that you update impacts a different component so to speak, right? Like, so

this was like a good test and as we played with the composition patterns, we started noticing interesting things like wanting to force suspense into the child components. Um, it was funny. I was

components. Um, it was funny. I was

working on a version and there's a guy in our Discord who just who really wanted to test Ricky's thing. So, he

just kept building examples in React.

Tons and tons of examples of composition in React to see, you know, where we would land and compare them to what I was like working at Solid. He kind of almost like nerds sniped me because I was just like doing my work and he's just like, "Why doesn't this work? Why

didn't this work?" And I'm like, "Well, does it make sense for this to work?

Should it work that way?" I'm like, "No, that doesn't make sense." So, like I got just dragged right in to spending like a week playing on the versions of this the this demo. Um,

this demo. Um, guys.

Yeah. Yeah, exactly. Thank you. Um

Um, it was it was it was very helpful.

Uh that's how we ended up coming to basically producing what I I'm very happy with um in terms of like optimistic updates and the whole thing.

But during this process during this process of working through this demo, two things happened.

And let's see if I can find the original.

Um, I got to go backward.

I've you I've used this demo so much.

Um, it's actually kind of funny.

Uh, let me go here.

Yeah. Yeah. Yeah. Yeah. Yeah. Look,

design async select like he's this is how they're pitching you consuming this stuff. But

stuff. But you know, like where you have like action action, right? But

the one thing that came through this was a spell version.

And thank you, Simon. And I looked at it, I was like, man, like now

this isn't generalized.

At the time that there's a solution to this now, but at the time that they made this demo, if you made this a general component, you would have to do this too. And that's a little awkward because

too. And that's a little awkward because when you change it, they both freeze where you really only want the second one this freeze. The solid solution I said isn't global pending is not sufficient. It's not quite good enough.

sufficient. It's not quite good enough.

But the key part that I want you to look at here is like the solid example. He

literally just has a stack of states that are derived. Right? If you look at I I don't have the exact solid example open right now. Um this one's a little bit more complicated um because it's got

the third drop down but to add the extra drop down all I had to do was add an extra select and add the similar state.

So just states derived at the top fairly straightforward exact same logic and then he just bound the data bound the

the setter the end. No transition the thing you just set the value and like I mean props. I mean, it doesn't get

mean props. I mean, it doesn't get slimmer than this. Uh,

to be fair, I would be fine even if it didn't have the data binding. I don't like data binding, but like just conceptually just being able to pass set state in right

now. Ricky's version has set state in

now. Ricky's version has set state in passed in because literally it's uh async design component and this is value action or something, right? Like like we

saw um we saw in uh the tweet that I was showing uh Ricky showed yeah like you know what I mean

like this right he is just passing uh I think where is it oh he's putting the data fetching in

line okay whatever it that's weird anyway um I I could picture a very similar type of solution because you've masked this away in the design

components but then I started thinking I'm If I'm inside if I if if instead of on click now I'm

using action. So I'm inside the this uh

using action. So I'm inside the this uh so this react thing right so where we are I'm inside add to-do action here I'm inside here

and forget that it's adding to-dos and await but if I do anything in here if I add if I set any state or do anything you know it could be related to what I'm

doing not related to what I'm doing like kind of related you are in the transition

you have spelt's behavior if if if if like essentially like not the same I I like react's behavior slightly better but like you have basically the same zone where you're everything's like

locked up you know um if if like that's your baseline the challenge is every single component in your ecosystem needs to migrate to this now to to actually

benefit this in a clean way. Now, this

can be a slow process, a gradual process, but if this is the future and the writing's on the wall, obviously if I'm React, I can't just like pull the carpet on people. spelts

like surprisingly pulled the carpet on people multiple times and no one really cares but um like [snorts]

you know I'm small small solid small too you know and I just look at this and I was just like while it bugged me that if I could like update two different states and it' all

get tangled together in the spelt version and like like why like like Like like I actually have an example. I'll

show you in a minute what I'm talking about. I I I just occurred to me that I

about. I I I just occurred to me that I was just like if this is the future, if we're just using this instead of on click, then

we're already in this felt world anyway.

So I I had to stop and I was like the last if if we're going to go this way, the last thing I want to do is is force people to figure out the when

they have to call transition again. Like

the problem is you're essentially introducing modes, you know, like you have like even if this hides the transition, I'm still thinking about

transitions because if I put it on click or versus action, I actually have two completely separate modes of behavior, right? Like

right? Like there there's no world that even if I hide the transition keyword that I'm not thinking about transitions here.

What's the JS output between the SL and SWAT one? Um,

SWAT one? Um, I mean, if you want to see, it's funny.

Uh, not that example, this example. Um,

JS output. What you're going to see is a bunch of compiled async. Yeah, look.

Promise all right here.

It's not. It's promise run. But like

they're compiling in stuff and organizing your code based on your async behavior, right? And then dollar sign

behavior, right? And then dollar sign async promises get this and then they like it's very much into the system, right? If I find the solid version of

right? If I find the solid version of the this original demo here, um not the more advanced one with the

triple. Sorry, where's

triple. Sorry, where's Yeah, whatever. I'm gonna have to keep

Yeah, whatever. I'm gonna have to keep track of tabs here in a minute. Yeah,

this is the triple one. I I love the triple one just on it side. It it this is But um if I look at this one and we look at the disc here, this is all the

library code as well. So I I can't quite play around it, but let's start from where our actual component starts right here.

Template code. Okay, that's fine.

If you notice the stuff above the JSX has not changed at all. It's just create async signal say in sync signal then create component suspense loading children do. You won't see anything

children do. You won't see anything related to async. So basically the reason it's solid version is completely runtime. There's no compiler

runtime. There's no compiler augmentation. There's no blocks, no

augmentation. There's no blocks, no promise all like it's it's it's completely like there's it's not analyzing your code in any special way.

It's just the classic, you know, create some render effects, create some components kind of thing.

So fine, I found myself 0% converted. Is

that a word? Well, I'm not I want converted to what? Like you I I I'm just putting the I guess the question is people are are they a I haven't really

gotten to whether the async features are worth it. And I'm probably not going to

worth it. And I'm probably not going to get into this into in the stream because this is one of the hardest things to show because Oh, you don't find it controversial?

Okay, that's that's fine. We haven't got to the controversial stuff yet.

I mean there's a little bit of controversy here, but you can kind of see spelt and reactor agreeing about something and

by doing a a little bit of a shift of mentality of what's first, you you kind of end up in a in a in a fairly different place, which is kind of

interesting. Like it's similar, but it's

interesting. Like it's similar, but it's different. Like I was talking about how

different. Like I was talking about how in this example um in the React example here once you're in here you're in the transition. Well, React has a solution

transition. Well, React has a solution for that. They have special optimistic

for that. They have special optimistic state and I think that's still a great solution because basically you define the quality on the state itself. You have state and you have like

itself. You have state and you have like optimistic state right and depending on that it behaves differently so that you can just call the setters you want in here. So everything can live in the

here. So everything can live in the world. That's your that's your trick.

world. That's your that's your trick.

Like before they used to have used deferred value and stuff and you do these it was actually more complicated and you do these things where you'd have to write something outside the transition and inside the transition essentially if you wanted to do like a

type ahead or tearing or something create optimistic or use optimistic. The

beauty of it is you can do the set in the transition which lets them compose it like this. My so it completely works.

There's no shortcoming of just making everything like a transition like this.

The only shortcoming is the refactor cost which is something you that you have to do as React but something a smaller framework would have to like it'd be more expensive probably on the

like because people haven't really opted too much into all our async features. It

it'd be more expensive for people to probably uh refactor cost um than it is to change the behavior here. So someone

asked earlier if if I saw a bunch of breaking changes. The challenge is it's

breaking changes. The challenge is it's not API changes, it's behavior changes.

It's like when React changed to calling set state after it's it's it's it's we can keep the exact same API except for

splitting effects essentially. Um

but but the timing changes which I think is arguably harder to detect and actually bury breaking. So it's just the but all the simple demos will like the

90% case will all just work the same as it always has. Do you know what I mean?

like it's it's just the last 10 become really hard to narrow down which is scary.

But you won't need to refactor most code if it's written in a good way which is an interesting dilemma.

The thing is yeah t sorry dev response tack is acing in the component. Yeah, the thing is most of the things here are about async

entering the system. It's

how should I put it? Our systems still are set up to be mostly synchronous perceptually, but kind of like how you have async await which kind of gives you that illusion that you have a continuous flow. That's what we're looking at here,

flow. That's what we're looking at here, right? Um but we haven't got to the

right? Um but we haven't got to the solid solution yet. Um to be fair, so I I I I need to continue I guess.

Yeah, I mean caching can be part of the solution but mechanically at a fundamental level in order to get these features that you know you like stuff like Tanstack should actually be tapping

into React's render model. hard because

of like they have their own storage considerations.

But this is why stuff like transitions and suspense exists so that third party libraries can just tap into it and streaming just work. Like we had an incredible integration with tanstack query where like literally you could

just go into solid start put tanstack query in use that as your datalay layer instead of like our other stuff and essentially streaming just worked instantly because it was built on our premise switch to handle the

serialization we had the building blocks already there so everything just like it was literally just like no thought and I think that like that that's why even with local

person all these things the async primitives in the framework are incredibly important because that's the interfacing point like tanstack query

like how does how does it get from promise to state we help it right that that's on us okay so like so

far like you now you're kind of like at my starting point and I'm sorry it took almost freaking two hours to get there but um Like

I I was pretty convinced here. I was

like, I have to drop everything I'm doing to look at this.

Like if this is the future, how could we look at this any other way?

Like tricky.

I knew there's parts about spelt solution that wouldn't apply to us. I'm

not going to rely on a compiler. Someone

actually came to saw Discord and was like uh you know today or was like talking about compiler stuff and I was like no not not going to rely on compiler but can we do something different than what React's doing here?

Right. That that that was my kind of baseline. Um let me look at my notes and

baseline. Um let me look at my notes and see where we are on it because we kind of jumped around a bit.

Okay.

Okay. I know where I want to go next.

Okay.

Um, we did talk about what transitions are and why they exist. Does anyone have

questions about why they exist? Like why

it's valuable to be able to hold in the past. Um,

past. Um, I'll leave this one.

You know, like I think like it's easy.

We understand optimistic and showing the future, but that only really works on mutations because you know what you're going to change.

We we all understand tearing because we've done this a bunch, right? Like

it's just kind of the default. You fetch

it in use effect, right? like here

terror it's 3 * 15 is not or 3 * 16 is not 45 but it's going to show that for a second you know especially if I slow this down more

right 3 * 3 is not six um but sometimes we do want to tear right so that we can have a a loading affordance we understand placeholders suspens is

easy. The hardest one to understand is

easy. The hardest one to understand is hold in the past and why it requires such complicated solutions like transitions like

do you fun do you fundamentally understand hopefully what I was not this example um

what I oh did I already close the tab example down it's fine I'll do one here like why I'll solve it. Yeah. Why transitions

are are important here. If we want to like continue to have See, I don't have the counter on this example, but why we want the continue have this page live and updating while we load the next page off the other side of the screen. Right?

This is not easy to do. Somewhere

there's a conditional that that literally discards the one side and renders the other side. Having both

exist at the same time requires consideration.

Yeah, I mean it depends.

The problem is this is a trivial silly demo. Picture this was like a

silly demo. Picture this was like a shopping cart with prices and line items and like an invoice.

and that stuff took slightly longer to to update.

This is not what you want. There are

cases where you want tearing, but this this is not this is not one of them. Uh

Ricky has some great examples that he that he showed like a few weeks back on Twitter. I I covered them in previous

Twitter. I I covered them in previous stream and it's like when you kind of put them side by side you're just like you kind of realize like for me this realization actually happened when I was

working on React Native back in uh uh 2016 time period I was building a production app in React Native and um it was just kind of like the difference I

was looking at our existing native app and I needed to get the performance so I spent a lot of time performance tuning but it wasn't just that it was when I was looking at um

like the affordances and the way it work this holding kind of pattern and last dirty state was super common. I was used to the web like like I don't know if I can see it on Twitter right now, but I was using to the like

like all these like spinners and stuff on the web, right? Like you just saw the Twitter spinner and native wasn't like that. everything was smooth and animated

that. everything was smooth and animated in. Like I think the thing is once you

in. Like I think the thing is once you get the holding stuff, see the the when you have all the spinning, it's fine to have placeholder stuff like spinners and stuff, but when you have that, you can't

really transition the uh UI as much.

It's very common in native to have content to content, which means that you get the smooth looking animations. So

holding is actually kind of like part of the equation to to to get that like and animations in terms of transfer. It was

just when I started seeing those kind of things and then when I did the kind of like transition test with people and their perception of performance and speed actually even if it was the same speed or slower they thought it was

faster because of the way that it was like less intermediate states. Um, like

there are times and places for tearing, but I I I think I was okay with it being an often feature to be fair for the longest time, but

it's freaking it's really confusing because I think I think the reason it's confusing is because the dec like where to stick it in the chain is really hard.

Do you stick it at the the root but then it's not your decision or does every place that you want this kind of behavior need to like be opted in and then like what if something else comes related to

it gets like [clears throat] what mode you're working in becomes like at least with the the API that that Ricky put forward you're like I am in an action I

know that I am in this zone like there's a mode switch um free-for-all is kind of scary right and the problem is you think okay well what if I just zone the UI

like like say like this is consistency zone like the way we do suspense this is something that I I considered for a while too especially when we were working on the Marco team and it was like the problem is transitions are

global it's like it it's like inverse uh kind of situation like it's the things that don't get caught by suspense you know what I mean like it's the it like

technically what we there's like a mechanism in here where new suspense um actually goes to fall back and like so you can

break out of of transitions by using suspense. Um,

suspense. Um, but like it's the topmost level. So zoning it

doesn't make a ton of sense because you you can't you have to be able to provide the guarantees at the top at the level. Like

if someone wants something to be consistent, that is a global thing. Um,

you could opt into tearing, but opting into consistency doesn't really work like from a like a zone style. You opt

into consistent like with a transition by wrapping the whole action from right all the way to end. Not from a zone of the UI. It just Yeah,

the UI. It just Yeah, hopefully that makes sense.

Um, where was I? Um,

sorry. Let me grab my notes again. I

kind of got on a impassioned thing there. Okay. Yeah. So, I think

thing there. Okay. Yeah. So, I think I think we talked about transitions and why. Yeah. I I think I think I'm hoping

why. Yeah. I I think I think I'm hoping people kind of get it. Um, but that is a great question. I'm I'm glad you asked

great question. I'm I'm glad you asked because I I spent so much time like thinking of like every random way like okay we don't need transitions if we bake stuff only into the router. But even when I was

trying to bake stuff into the router it this this even if you like kind of manually manage the fork yourself of the next page. You

need it to go from being like special version to being the version and like swapping it in and then everything ends up flowing through like this top level

API interface like it it just didn't work with any level of nesting like so I was like I tried to avoid transitions for like a year uh because

they're in one solid one and I was like man these are complicated they're buggy even in solid one they're they're buggy I'm like I didn't want to go there again and then I implemented them completely

ically one way using forking of the graph which is like my ideal form that I thought like what I'd learned like in solid 1.0 0. When I first released it,

we had transitions um which kind of just added some extra transition fields onto the signals, but the graph shape kind of stayed the same, which was awkward cuz then I had to like make this custom code

to around disposal and like trying to figure out what I was doing. And around

1.3, like the 3 months after uh solid one came out, I started working on like a a better uh approach that actually cloned the nodes and did forking. I got

like decent place. Um, and then Milo kind of took over. Um, and I kind of moved on to work on like other features that I needed to for Solid. And then

Milo disappeared for a bit. To be fair, he's in he was in school. Um, but when he came back, he's I'm like, "So, how did the transition stuff go?" And he's like, "Oh, I stopped working on that and

I built a a different signal library uh called Reactively that does everything lazily and blah blah blah." Like, which was good because that kind of triggered

the whole like signals thing in 2021 like the or um I guess was it 2021 or 22 like when Preact and all that came out

it was like right after Milo was doing all that work um and uh essentially that solution never worked and then I

just remade one of that design that actually worked and now I'm talking about as I said a fourth version to these these uh transitions

thing that doesn't make sense to me is if you have a state graph that can be independent of the view react can why not have the view be the thing that it's holding optimistic etc well

consistency of data flow and cascade of like like to be fair I we don't you're right and in a sense it is the

view that handles it in the latest model that I that that I'm working on. Like we

need the like the blocking behavior to prevent waterfalls. But if you actually

prevent waterfalls. But if you actually look when we get into my new solution, it's only the render effects that are special.

So yes.

Oh, come on.

There we go. Sorry. Streamyard sometimes

freezes up some kind of instate graph.

So I think there's actually different path here. It sounds kind of like zoning

path here. It sounds kind of like zoning you mentioned. I don't fully get the the

you mentioned. I don't fully get the the issue here. Well,

issue here. Well, it's cuz for something to be consistent, it has to be universally consistent is kind of like the problem.

Well, transitions don't need async local storage, but to be fair, actions still have the same problem like like when

you're doing an a mutation because it's not tied to the graph. But we'll we'll get there. Okay. So, this this is good

get there. Okay. So, this this is good because this let's let's talk about consistency for a bit cuz we've already kind of talked a bit like one of the key parts for transitions was splitting the

effects because I wanted to be able to run and know the dependencies up front so that we could like make decisions especially in the case of lazy systems be able to pull and know you know like you've hit all the async stuff and that

it actually is because because you could be your effect could be under a suspense boundary and not trigger the transition.

Like there's ways that you can opt out.

you actually have to wait until it propagates down to the effect which means you have to run the effect to actually know and then by then kind of you know it's it's too late if you push it off. So you actually that's why split

it off. So you actually that's why split effects you know have become a thing.

But um what I wanted to actually talk about is about consistency in general and and we should I wrote an article a while ago. Let's see if I can find it.

while ago. Let's see if I can find it.

Consistency cost of consistency in UI frameworks.

Maybe not nearly as popular as it should have been but who knows.

This is a I made a very simple example in React.

We've seen this before. State memo ref and then I set some state and I went log log log log and I made this example in

view. I made it in spelt three and I

view. I made it in spelt three and I made it in solid and we all got different answers.

React was 000 because it doesn't update it right away. Vue was 120 because it updated you. It got the most recent

updated you. It got the most recent count and the most recent double count, but the DOM hadn't updated. Spelt was 10 0. Spelt updated the count, but this is

0. Spelt updated the count, but this is before it had signals. So, no way of having the drive state until it ran the component again. Like spelt used to be

component again. Like spelt used to be almost like a VOM until version five.

And then Solid had all the dates up, all the numbers up to date because it was the same. It was it actually just

the same. It was it actually just flushed right away when you did account.

It just unless you opted into batching solid I basically made a hedge when I made solid that that because we were fine grained enough like the updates

wouldn't be that expensive and if you cared about it you could dispatch. Now

dispatch. Now this is an interesting thing because over time solutions have changed. spelt now is the

same as Vue here with spelt 5 and solid 2.0 know what I was working on until um you know a few days ago is actually

the same as you as well. We all kind of collided it just we're like it's okay we understand we had to acknowledge that there was like an inside and outside the system which is something that you know

is worth kind of talking about. As much

as I love one 1222 and 000 because they're both consistent, 0000 causes people to throw pull their hair out apparently, you know, because they're

like, I set the count. Why is the count not updated? Right. And um one 0 is just

not updated? Right. And um one 0 is just weird. Although at one point in this

weird. Although at one point in this article I'm like maybe we just go with it because it's like it's it's like kind of native. You set the count, you see

of native. You set the count, you see the count, but then you keep the other stuff in the past. But I was really debating through this because in solids batches we worked like react essentially

if you used a batch you got 000 um and my conclusion for solid 1.5 when I finished with this article sorry did I did I did I post this in chat did I

forget to post this article in chat let me let me see if I oh no I did I did I posted in chat my conclusion in the end was that solid

after this changed was 122 view 2. And

when you're inside the batch, it's the same as view 120. We would do early work if you read like basically if you never read double count, you know, here we would defer the work until the end of

the batch and do do it then. But if you didn't early read, we we knew from the notification of the signals that it was dirty, so we could we could do the work ahead of time. That's that's kind of

essentially where we landed. Um because

batch in Solid used to be like this and it used to drive people crazy. You know

what else is like this? transitions

because uh there's a the reason for this because of like async but generally speaking um the signal world has moved to views

model 120 and reactive state is 000 right and I I talk about this like there's ways to get the other numbers in the other systems and

people have their different opinion some people were like temporarily invisible changes X consistent with lazy recal like this Jyn who made a mole or whatever

um uh was like views the only right way and I think a lot of signals people felt that that way but yeah see he said solid's consistent but

instant recalc isn't optimal like there's no winning this battle I I mean temporary invisible changes is that a problem I don't know it depends really

put into emphasis that in all these cases the reactive system because of of the smart like how it renders and how it runs in order always saw the same thing

in all our systems the reactive system always got ran once and got the most update to date values by the time you get to doing the DOM you have all the right values in place and it like

there's no problem there this only matters inside your click handler and or maybe inside of your use effect callback back. But essentially, because the

back. But essentially, because the reason that that's the reason why this article came up, solid batched our effects automatically because we didn't want to like freaking it doesn't work to

be all jittery when you're in the process of queuing running your effects queue. And we had this 00 behavior which

queue. And we had this 00 behavior which basically drove a lot of people nuts because they'd be they'd set the signal and then they read the signal and like why is this not updated? And it was really confusing for them.

Part of me knew that making this decision might be a mistake sometime down the road, but this was like it was

like an okay concession, you know.

I mean, 1 1.20 is easy.

like it's the most obvious thing to do with signals. The problem is one 120

with signals. The problem is one 120 um the problem isn't that one two is easy.

The problem is that um and not even that it's inconsistent. It's that when you

it's inconsistent. It's that when you add async, it can no longer be guaranteed, which I'm going to get into this in a second because I I

let me show you.

So, we're now all one 120. And then

let's let's look at this. I'm going to show this example.

I remade our example installed. And

let's add the console in here, too. I

didn't do the DOM ref. We all know the DOM's going to drag behind. We don't

care. So when I click this one, two console log one two. Not surprising.

Yay. 510. We get it right now. The most logical thing for a

now. The most logical thing for a signals library is is to have this behavior. We're used to it. And then but

behavior. We're used to it. And then but let's throw a wrench in here. Let's

let's make double count drive. It's now awaiting to do it.

Now I'm going to hide the console for a second.

We know that spelt will hold it. So

we're going to see a second, half second, and then it's going to show the stop like as you expect, right?

Sweet. That makes sense. But look at our logs here. We're back to one zero like

logs here. We're back to one zero like we had before. Um, let me just toggle this again. Okay.

this again. Okay.

And what happens if I click really fast?

Oh, 1 0 2 0 3 0. I mean it makes sense.

We don't have the async value. We can we we can only show uh what we have, right?

So the and the point is this is pretty obvious that this delay is happening here but we we already saw from our uh our other example that because like you

know we're holding state or other drive state like if there was a a an async triple count like drive count like if if there was a chain they would all get

held as well. I I mean maybe that's a better like maybe that's a better example.

Let's let's try this double count.

Let's let's do this.

Did I Did I screw something up?

Oh, they're warning me that there's an async waterfall.

Does that make any sense? There's no

waterfall. There's only one await.

Let's put quad count in here.

Okay. So, this this deres as far as it can go. I I suppose if I move or if I

can go. I I suppose if I move or if I move I guess the better example is if I moved it here and then I remove this here.

And like let's pretend our event is not aware of double count. Someone like like you know what I mean? Like I'm just saying we added a weight somewhere and now

we we're not aware of double count in our component. We only got quad count.

our component. We only got quad count.

Okay.

We click and we're like oh what happened?

My point is if you depend on this behavior of derived inside your event handler or or whatnot like pretend it's

not adding a number. Pretend you derived something like length and you removed an item. You removed the last item. So then

item. You removed the last item. So then

you you look at derived pages length and you try and index a value that's missing in an array and it actually crashes on

you. This is possible, right? Because

you. This is possible, right? Because

because because adding async compromises your ability to show derived values early and it could be somewhere downstream. It could be

like I I it's hard with a simple example to to do this because it's like, you know, like it's right in front of you.

It's a simple example, but like it's it's it's possible that the difference between this this being double count and

count is the difference between you getting zero for your number you care about or you getting the correct result.

And it's especially confusing when count is updated too. So like

I I there's only really one way to think about this. It's it's that

about this. It's it's that there's a difference between being inside the system in the reactivity and the rendering and the components and being in an effect callback or in an

event handler. These are different

event handler. These are different zones. So it's not different modes,

zones. So it's not different modes, different zones.

Right. I mean the what you end up doing is you I don't know does spell have an unsettled or like a a weight tick or some something like that. You end up you

the only thing guarantee that you that you you basically go um I'm just going to let it resolve out and then I'm going to do it. Right. that there's there's a

there's another mechanism swelt has where you can ask for eager but you can't you can never get what you don't have right this is just the reality of async

this would happen with solid today but if you added a resource in between it it would yes this is I'm not picking on salt here I just want to comment here

so you kind of start understanding how Async um sort of throws a wrench on your expectations. Now, don't get me wrong,

expectations. Now, don't get me wrong, it does not impact any of this logic in here. Your component, your actual like

here. Your component, your actual like way you wire the graph, the way you build out like your UI is not impacted by this. You have perfect guarantees.

by this. You have perfect guarantees.

Everything runs exactly as you expect.

It only impacts stuff outside the system, right? And I I think this is important

right? And I I think this is important to understand because like there's consequences. Do you know what I mean? Like you

adding async somewhere if you don't account for that here

can cause to error to crash.

You could separate this in space, have the async somewhere else, and this code can error because someone changed a dependency or added a dependency or did something.

Signal isn't the place for async. Well,

it I mean, I'm I'm not saying that. I'm

just saying like this async if you have inconsistency you can cause stuff to break. Uh do you want to know like want another example? Um

sorry give me a second here. No, not in here. Uh

here. Uh um let's see what it Oh yeah, I copied some code.

This is just illustrative here. So,

let's not like I'm just going to copy this into a empty playground so we can just look at this code. This was dropped on me uh when I was in uh

on the Discord and you can see what I'm talking about. This is some solid code.

talking about. This is some solid code.

Don't don't worry too much about what this is. But the idea is you you got

this is. But the idea is you you got signal, you got some async, you fetch some value, and then you choose to show the button

based on whether the value is set. So initially

it's zero. So value is zero. So there's

a button that lets you do something with the value otherwise not. Now my question is person clicks the button right sets it

to one and this takes some async time.

Now we're in this universal transition world where the stuff is all, you know, still present and alive and stuff. And

so this is still true even though this is no longer true. And someone calls this button. They click the button

this button. They click the button inside. What is what should value be?

inside. What is what should value be?

Should value be one or should value be zero?

Uh, I I you're you're asking the right question.

Yeah, you these are all fine things. You

could say wait for it. I'm saying but your existing code has to be aware if someone goes and this this has been one of the most interesting challenges with

doing this is we're creating seamless async yet that only works if people don't have to refactor their existing code

generally or it's not that they might have to refactor and this is fair on your point well you should you know put the weight or whatever it's they might need to refactor their existing code but if they build with best practices. The

addition of async should not cause code to have to change that is because it's too permissive within the graph.

You can sync with a resolve helper. But

yeah, I I just wanted to throw this example. I want us think thinking about

example. I want us think thinking about this right now. single wrapping promises is an

now. single wrapping promises is an option because then you could like always force the waste in but that also has some interesting consequences in terms

of like API shape because now you're taking signal of value or promise of value like generically from a component comp composition to be fair I've been

seeing a lot of that happen in React but you all know I mean this is this is my own constraint I'm putting on here I want it I want Uh I've been working on

on a system where async is colorless. So

that is one solved but but you know in this version this could be a async or

not async you know but you have to know to do that. Yeah.

But the TypeScript tells you, yeah, the trickiest thing is you can do that inside the reactive system. That's why

the reactive system has no problem. But

in an event handler, you're no longer tracking. You don't rerun events.

tracking. You don't rerun events.

They're they're not expected to be reactive. They're kind of outside the

reactive. They're kind of outside the system. I I I'm I'm doing this on

system. I I I'm I'm doing this on purpose because I I want you I want people to see that there is a definite inside and outside the system. There's a

zone in which the inside the system which works seamlessly beautiful. The

decisions on the outside are all messy because the the reality is we live in an actual like the JavaScript is a

different world than what is inside our frameworks. Now React has always been

frameworks. Now React has always been very simple. like it's our components.

very simple. like it's our components.

That's our magic zone, you know, where we where we control and have different rules.

In our case, it's our our reactive graph, right? In Steel's case, it's

graph, right? In Steel's case, it's wherever we choose the compiler to touch.

Um, but like the it it's I just wanted to kind of like I'm I'm not necessarily what the right answer is, although I suspect that this

should say zero here. That's my my gut feeling. But like th this is the kind of

feeling. But like th this is the kind of consistency thing. And if for this to be

consistency thing. And if for this to be zero traditionally or at least as a default then you really have to think

back to the only way this is zero is if this is zero right which means I mean surprise. Do you think react

thought of this issue 10 years ago? I'm

willing to bet they did.

we'll end up with manual fine grain reactivity. Well, I mean this is the

reactivity. Well, I mean this is the thing, right? If if you really really

thing, right? If if you really really need this capability, you're going to be calling flush, you know, or await flush, right? Like which I told you that remix

right? Like which I told you that remix would come up on here. you'd be calling update you know if if you really need to know you'll be like my gut is if you

write code in a certain way you shouldn't have to worry about dried values so the thing is whatever you set you have right here like wherever you do the set you have the value set so you don't need to read from the signal again

in most cases there are a couple exceptions uh especially around like control inputs and stuff and there's a solution for reading the latest value without having to wait on it but for

most things you are.

If you really need to see the result of your work, you're going to call flush or call update.

Rick can not hear confirm. Yeah, I don't I don't know. He He said he'd check it out, but maybe he'll check it out later.

So, transitions and forking. Well, I

haven't got into that. I The interesting thing is spelt doesn't fork.

I mean, they have a fork feature that they just showed off on blue sky the other day, but spelt's transition behavior doesn't fork. They literally

just hold the effects based on the compiler with the DOM zone, and they they must handle their cleanup in a different way cuz I think it's cuz their conditionals

are built into their templating language. like if blocks aren't a

language. like if blocks aren't a generic reactive uh mechanism. They're

literally like their if and each are literally like blocks within their like UI framework. So they can they hold

UI framework. So they can they hold based on blocks and spelt basically uses the fact that it knows that it's rendering UI and using its advanced compilation techniques to accomplish

this which I said isn't very helpful because solid doesn't really care what you do with the signals.

Yeah, I'm I'm not Yeah, I'm not I'm not sure. Um,

sure. Um, so yeah, he's not Well, the interesting thing is it I I that I am actually arguing that

that is the case. Inside the system, it doesn't matter cuz inside the system, if something's not ready, it throws. So

when you're like and it doesn't throw the whole component, it just throws inside the graph. That's if you if you've ever seen my uh um let me see if I can this site. If you've seen my

beyond signals like nested fetching example in solid, I I literally just have a component A render component B

and fetches its own data. B fetches it own data and render C and C fetches it own data and renders its own information. And these all happen in

information. And these all happen in parallel because it's not blocking. We

only block the expression where it's read. So B fetches it renders throws in

read. So B fetches it renders throws in here but still can render the rest. C

fetches throws in here renders rest.

This is like native to the solution.

It's funny. Uh, spelt actually recently released the same demo, but and I was like again I I was like he called it out of order rendering or some like fancy

name and I'm like isn't I I was confused by it because I was like like for us it's just a property or reactive system because we're fine grained. It's felt

because they tied their async to the blocks they actually had to come up with a really like clever solution using their compiler to actually accomplish the same kind of parallel behavior by like analyzing and figuring out how to

slot it. for for this. If we look at the

slot it. for for this. If we look at the actual generated code, you're what you're going to see is

like create async, read it down here, create async, read it down here. Yeah, there's some like

down here. Yeah, there's some like element walking, but literally no special case code. This is literally just how the reactivity works. And

So called a time travel didn't this your version not small world sync asynch this is probably the smallest it can

are there visualization how the graph lives while updates um uh solid dev tools does that it actually shows the signals and then you can see I I I I would love to see if we could like link

in the IDE it would be really cool to like when you like trace like what causes this the update or whatever ever. It'd be be cool.

Anyway um what what I'm Yeah. What [sighs] kind of Where are we still? We're talking about Yeah. talking about this consistency

Yeah. talking about this consistency example. Ultimately,

example. Ultimately, this is where the controversial part is, right? Because

right? Because essentially I was saying that like splitting the effects

maybe React was on to something.

There are cases though async still blocks the commander can't help there.

Yeah I yeah I believe so. Uh I I I don't I haven't created those yet, but it's just like this is a kind of difference with building into the reactive system.

It's so fundamental that it can't work any other way where if you use a compiler, it's a best effort optimization.

Um sure, but man, who wants to write them? Yeah. Um okay, so

them? Yeah. Um okay, so I I I became very aware of this when I was working on um when I was working on on some of the the

when I was playing around with this new async signal stuff that I still haven't even got into showing you all yet, but isomorphic We'll talk about that.

Sorry, I have to jump a little bit in time. Um,

time. Um, the worst part of API design is when the answer is the one your users will hate.

They will never thank you for it. They

will misunderstand it until the end of time, but there's some comfort in them never knowing the pain they may have faced. And people actually asked me for

faced. And people actually asked me for example, so I gave two two examples.

splitting tracking from depths and their side effects, not applying the value immediately after set state. I've always

been able to argue the correctness for these, but chose differently for convenience. But what happens when

convenience. But what happens when ambition grows in convenience turns liability? This was me talking about

liability? This was me talking about this because the truth is with async involved, the only way you have any guarantee is to

delay the way React does, right?

It's it's kind of just one of those unfortunate truths. It's I don't think

unfortunate truths. It's I don't think it's actually debatable.

I'm only talking about outside the system, right? Outside the system can

system, right? Outside the system can have different rules. Like we could technically you could do like like what Sel 3 did and only update the initial state and not update the deres. But you

have to understand that the derived states may not update. And this example that I showed here really really

suggests that as a default you probably should um also keep the set state in the past as well cuz this is what happened in

transitions. If you remember if you have

transitions. If you remember if you have a transition and you set some state inside it if you try and read that state outside the transition it's still the value it was before it changed it like this is intrinsic. So if you remove the

transition wrappers, remove the boundaries, then you you're basically always in a transition.

So it kind of makes sense. It has to operate that way.

Well, deferred updates can stop some of the throwing issues even in handlers. Is

still possible someone reads from an asyn?

outside of the system.

See like an in effect the dependencies are tracked, right? So you can you're not outside of the system. It's only if someone triggers an event handler that's off screen

basically.

Convenience turns liability is the name of the spelt four to five album. Yeah,

definitely. I mean I think React is definitely sitting there and going like told you so a bit like especially when spelt changed uh you know a bit you know

the funniest thing is like it's not so simple like react compiler is has a lot of similarities to spelt 3 so like but see react doesn't really have to

worry about a told you so moment unless someone convinces them to switch the signals which I don't think is going to happen and we'll look at a bit in a No, this is the same model that I've

been talking about for ages with the throwing. The thing is initially,

throwing. The thing is initially, initially when you're rendering the UI and you throw, it doesn't have a value. Afterwards, we

can treat everything as in the past.

It's only initially that this is a problem.

Um and I'm kind of banking that in the majority case, the data that you would read in an event handler is the same data that you

would have in your view. Like show this thing with this data and then it's like do something to that data. I mean, it's not the 100% case, I understand, but it's something that I'm okay with. I I

know we've been debating this for ages, but um as I go farther, I become even more convinced.

You could start coloring the async everywhere but it it doesn't the cost of that migration is huge.

There's even React kind of like even though they're talking about passing promises to a certain degree the reason you have these mechanisms is because we don't want to be awaiting everywhere.

Now it's possible outside the system that you have no choice right but inside the system you don't want that.

You saw the error insult when you didn't read the async data in the template it crashed rendering. Oh, really?

crashed rendering. Oh, really?

Oh, that's what that happened, huh?

Yeah. I don't know.

Okay. So,

I told you this is going to be controversial cuz because obviously I'm saying from an API standpoint, maybe React was right. I knew that people weren't paying attention to this post

even though it got 120. So, I did a poll. I was like, if I had an approach

poll. I was like, if I had an approach for async that requires no rappers, no compilers, no non-blocking, and render, no coloration, just works, but it requires set single and drive values to stay in the past until flash like React,

would you take it? And don't don't let don't get me wrong, this was a bit of a litmus test. Basically, there's only one

litmus test. Basically, there's only one wrong answer to this poll.

Um, you know, I think saying no, Async is not worth it is perfectly legitimate. I

I respect you for having that thing. And

I think if you're this person, it means a lot less React users responded than I than I would have thought.

Yes seems good means that a lot of you guys just trust me, which makes me feel good.

No, React is the worst is really the only wrong answer. Um, so this was a test.

Fortunately for you all, it was it was anonymous, but it's interesting. Do I

see the same on blue sky?

Uh, okay. Where was it? Where's my

profile here? Profile. Yeah, I did the same thing on Blue Sky.

People on Blue Sky seem to like React more. There's less votes, but it was it

more. There's less votes, but it was it was interesting.

There's a lot of react hostility on Twitter maybe, but it's just kind of funny. Anyway,

funny. Anyway, um almost the exact same ratio of people who trust me and yes, used it. More

people who say async isn't worth it. I

just thought it was interesting.

React is the worst is always right. No,

no, that that is not always right.

Then baby Ram took a bunch.

Yes. Yeah. I think it's but the people are dramatic with the bias but even the real answer is async isn't worth it.

Yeah. So I I do have to consider that that I think saying async isn't worth it is a very respectable position to be in.

I just it is very interesting when react and spelt think async is worth it. Then

again like I I don't expect Vue to come around here but Vue is hard. it view is hard to judge because they're rarely like on the cutting edge of innovation

so to speak like DX stuff happy users Angular 2 like very good at taking care of their developers but not where I usually look for for ideas

react very driven to the future and so it's spelled as of recently so definitely worth taking notice This what do I mean by set signal? I mean I

mean this set signal. I mean like if I call this and then I go console log,

right? So if I go here and then I go

right? So if I go here and then I go console.log

console.log value what is this?

If the answer is zero, that means it's staying in the past.

But if you stay in the past, that's bad, too. You click a button on a new page

too. You click a button on a new page and act like you're on the old page.

Well, internally, it doesn't stay in the past. It's only It's only the basically

past. It's only It's only the basically the user interacts with what they see.

is the way to look at it. Internally,

the system can get ahead of itself.

It's just that if you if you're showing the past because you're like holding or in a transition, what you interact with is also in the past.

Oh, yeah. I'm missing a second. It's

fine. It's not a working demo, but yeah, I'm missing a second. Thanks,

Right. The immediate

Yeah. The the immediate thing it's is easy. And often

easy. And often you see no getting the future value is easy too though.

You know Do you know what I mean? Like

you could do the same thing. const new

equals to set value new console log you know I mean new is a JavaScript keyword so I can't use it but

you you get [clears throat] getting either value is easy in the scope. What matters is when you're no

scope. What matters is when you're no longer in that scope. Like like in this example, like when you're over here,

right? And I don't think like

right? And I don't think like generically we I mean you could do try and be really fancy based on what flush it was on and like say like this click handler comes

in at a different time. So like this is part of this like it's possible a little bit. Yes.

Yeah. You you need to be able to say like do this when I'm done. But again

it's okay because it's outside the system. Inside the system everything's

system. Inside the system everything's seamless outside the system. You just

need a way of saying like, hey, when this is done, continue. I'm going to set this up and

continue. I'm going to set this up and then when it's done, I don't know how many cases are actually where that's actually necessary

cuz a lot like you have two options. You

can basically do the stuff all up front and use your intermediate values that you have on hand and then you don't have to wait till it's done.

The only time you need to wait done is like when you're like reading from the DOM or like controlled inputs. Like

there's there's situations where I can I can see it. But

transitions don't have isolation levels.

Now, yeah, I mean, we could talk APIs in a minute, but you you conceptually get get that the I'm really trying to double down on this outside inside the system

thing.

Okay. So, where am I next?

Yeah.

Okay. Well, then I I'm actually ready to actually get into the the main topic now.

I mean, have you seen any I I I mean, maybe this a good refresher. The demos

that I've been doing for the last little while actually show this off quite well.

um graph power.

Just a quick refresher on create async before we get into the new APIs. Um

because this is because you're creating a graph, we can still use stuff like error boundaries to catch errors.

So like it propagates along the graph because the whole thing is a graph. So like if you if create async errors in the same way that async propagates errors

propagate and then phrase errors.

So phrase errors then upper phrase errors. We don't care if these things

errors. We don't care if these things error so much unless we're reading them in an effect right unless we actually reading from them. So if you read from them in a

them. So if you read from them in a render effect an error boundary will catch them. So every so many clicks this

catch them. So every so many clicks this is going to error out.

It's random. So give me a minute there. Aer out. Right.

there. Aer out. Right.

What the cool thing is because we familiar with the graph.

This is kind of crazy to React developers because like this only renders once. It's possible for us to

renders once. It's possible for us to like obviously when I click again, we can update the signal and it might not error the next time and then that signal will get all the way down here and render the right thing, right? But

what's really cool is this retry button, which literally it's just a reset coming from the fall back. It's no clue what's going on. It just knows it's errored.

going on. It just knows it's errored.

Well, when it resets, it actually tries to pull at the nodes. It kind of goes, "Okay, well, this node's errored. What

what what's going on?" So, you click retry, and it, oh, it's errored again.

Click retry. Oh, it succeeded. Because

it it was able to trace the error graph and goes, "Okay, you're errored. So, I'm

going to recalculate your parent. You're

errored. Going to recalculate your parent. Oh, you're async and you

parent. Oh, you're async and you errored. Well, there's no solving that.

errored. Well, there's no solving that.

Let's fetch it again.

So, we're able to use the reactive graph to inform uh based on the error.

Simple. I mean, we have the the we have the committed the pending value. So, in the case of rights, you're inside a a setter. inside

the setter um we will give you the the um eager appending value because you need it for like mutation you you need to be able to like push something then add something and do that. So inside the

setter you will have full access to the eager value. Now you might be like what

eager value. Now you might be like what if like what if it's dependent on it it's it's tricky because what what if

it's dependent there's a certain point where like you could be writing to um like it can't give you the eager value if it doesn't exist yet. Do you

know what I mean? Like it can give you the eagerest value it has, but it can't give you it can't give you the it's possible that if something's in

flight and you write to it while it's in flight that the thing that comes when it finishes overwrites what you did, right?

It can only grab the the value that's latest available to it, but it will try inside the setter to grab the the latest value. And that way if you have multiple

value. And that way if you have multiple mutations like you're pushing or adding like something in a store that will still work. It'd be very weird if you

still work. It'd be very weird if you push to a store and then access an index that should be there and isn't there.

I mean this is create async signal create async. It's it's derived. I mean

create async. It's it's derived. I mean

unless you mean like we you can always drive from it to make it mutable but there's no real point to okay but anyways what I'm getting out is errors are just handled naturally

through the graph to their source where either you have a user effect where we can have like an error handler um it's a as a callback or we or a render effect

which gets caught by an error boundary.

Just sort of aside, but this is kind of this basis hasn't changed in the last several months. I'm very happy with the

several months. I'm very happy with the way the graph translation goes. But

[snorts] let me pull up my hackd here.

We did cover this on the last stream.

It's been so long on GitHub.

Okay sweet.

Yeah, I covered this in the last stream, but I want to refresh people on this a little bit.

All of this led me to saying what happens if you design an async first framework right?

I this started as an idea, but I had to drop what I was doing to test this idea, right? So, first of all, we talked about

right? So, first of all, we talked about this everything would be transition transitions implicit, not recurren API.

You'd opt out of async into tearing like we do with create optimistic, but the default would be always on. This means

no click action. On click would just be a transition and even the backside of create effect. Okay. Right. What I'm

create effect. Okay. Right. What I'm

saying is if you want to have tearing in this world, you might need specialized state. But what was interesting for for

state. But what was interesting for for me is uh couple realizations. You only

need optimistic state for data you don't have yet.

Um because this was the break point when I figured this out. You can determine what's pending state by just asking is pending. Wouldn't apply to things

pending. Wouldn't apply to things downstream from the async portion of the change. But anything from the start of

change. But anything from the start of the change that hasn't settled set the next tab but can't see the change yet is pending would return true for it. So

what I'm saying is is pending just means you haven't committed a value. It could

be because it's async. It could be because it triggered something async.

But and once I realized that this was the case, it it became very very unifying from an API standpoint. like I

started already seeing this in my my other examples, but um

uh let me see if I can find an example of this. Um probably in my

of this. Um probably in my uh solitude experiments might even be in the tab example. I don't think I have it open anymore.

um experiments tab.

How do I show the pending in this example?

Because I'm using the global transition here. See that? I'm not using like use

here. See that? I'm not using like use transition. I'm using is pending and

transition. I'm using is pending and look where is pending is is pending tab.

I'm literally I'm not asking about the data that you're fetching. I just know that when I set this tab like I'm like if this tab is pending then the like

this is always the problem right if you I I created this pending originally to be like oh is this data waiting like is the graph blocked you know and that was cool because you could ask about

anywhere especially it would allow us to like not go back up to suspense you know and we could just tear and ask this question but the problem is like how do you show is pending for something that's

offscreen right the data fetching off screen.

How do you make that decision? And what

I realized was when I did this async first thought thing is as long as the value isn't committed like you're in a transition, then you also know that you're pending, right?

And I changed uh solids transitions to be able to ask that question. So it's

not just the the stuff downstream from the data. the stuff that triggers it

the data. the stuff that triggers it part of that kind of unit you can ask is pending about which means that now you have a unified API you can say like look you could be in your component and go

look is this pending you don't care whether it's locked in a transition you don't care whether it's because literally the data isn't there yet you'd literally just go it's not ready you can

you can defer the you know you can handle the loads indicator which is really cool for Ryan Florence's demo

which we we will get to Again, what the trick to is pending and yeah, no more set pending. The trick to

is pending is it's a graph question.

This is I love this because it's not on each signal. I mean technically in the latest implementation there is an under the hood that's on each each signal that gets read under this context

as shallowly. Um but this implementation

as shallowly. Um but this implementation is done differently that doesn't do that. Like it depends on the

that. Like it depends on the implementation. That part is not

implementation. That part is not important to deal. You can ask it about a bunch of things. It's pending this or it's not like and doesn't matter cuz

it'll and or this you know data like you can ask this about any expression in a typical solid manner. We don't want is signal right. I

manner. We don't want is signal right. I

I don't want signals to have a special API. I don't want you to feel like you

API. I don't want you to feel like you need to wrap something in a memo or computer signal to be able to ask a question about it. I very very much dislike making signals special. You

should be able to ask it about props coming in, right? You know,

props.options is it pending? You know,

yes, you can ask this question.

Okay, I just shortcuted it because it's already a function.

Will there be a special node like? No.

No.

Right. So I I'm literally just asking this about any expression. You can go is this pending. Now I'd already kind of

this pending. Now I'd already kind of gone down this path, but I when I was designing this, I was like, this is the key. This is the key. Spelt's local

key. This is the key. Spelt's local

thing doesn't work for composition. They

need this. They will probably add it.

I'm not surprised. like effect pending you. If they could have just gone

you. If they could have just gone disabled pending um cities, disabled pending states, like if they could just ask it about the

specific thing that they cared about, you wouldn't have this problem, right?

You don't want to lock this up right now. This is your only choice, right?

now. This is your only choice, right?

When you change it, guess what? You

can't keep changing it. If this takes a long time, you can't like change your mind.

No. Why?

What do you mean is signal? This is not a signal. It's literally the opposite of

a signal. It's literally the opposite of is signal. Is signal is saying that

is signal. Is signal is saying that something requires a specific wrapper. I guess your concern is that

wrapper. I guess your concern is that people will be checking for async but you will be checking for async anyway

because you like disabled like you you you're look if you build it okay I mean we can look at this in as first

principles I built this API um if you build an API uh I'm trying to think is is this one a better example yes this one's a better example I built

this API I and I just did the default thing. I didn't put pending state. I

thing. I didn't put pending state. I

just built this API. And let's go down a little bit from from this. Okay, let's

go down a little bit from this. And I

click on it and I'm like, geez, this is taking really long to update. What the

hell's going on? And you're like, oh, it'sing async, of course. What's the

first thing you do? You go like, oh crap, I I need I should show a loading indicator. So then you go and you show a

indicator. So then you go and you show a loading indicator, right? That's the

first thing you do. And in my opinion, you like in your head you go, "Oh, I should like it's not the initial load, but like it's the update loading thing." So you're like, "Oh, effect. pending." Like you're

you're going to go, "Okay, how do I show that it's pending? It's like the first thing you reach for and it's usually tied to like that disabled button or something." It's it's the default is

something." It's it's the default is you're like, you know, if you miss something, you're like, "Oh, this is weird." Oh, right. It's loading. And

weird." Oh, right. It's loading. And

then you just It's not It's not a identity question. It's like you do it

identity question. It's like you do it for a purpose to show an affordance.

It doesn't look the same. To be the same, it would need to not be a wrapper function. If you put a wrapper function

function. If you put a wrapper function in between, it wouldn't work, right? To

do is signal, you would need to like you would need to be able to pass something directly into it without a wrapper function. So you could like look at it

function. So you could like look at it like this this API is not a signal, right? Because a signal um

right? Because a signal um I mean I I don't even know how you get a signal out of this. I guess you would like internally

intercept all signal reads and then like but like it it doesn't even make sense, right? Because a signal would be a

right? Because a signal would be a single thing. Are you saying is they are

single thing. Are you saying is they are they all signals? Does there exist a signal in this? This whole API doesn't work for is signal.

Yes. And props. Wouldn't work unless this was like was literally a signal on the end. Like a getter wouldn't work.

the end. Like a getter wouldn't work.

Yeah. Uh kind of like that. Like depends

on the implementation. I've done two completely different implementations, but yes.

Yeah, we do tag it on and we're like you're part of this transition and then yeah, in any case for composition place and localization,

I think it's super important to be able to ask the specific question like like is it are you waiting on like if you're making a select component, it's

very obvious. You're like you you the

very obvious. You're like you you the thing that you might care. like disable

the select list if if or make show loading indicator if I don't have my options to choose. That seems like something that's very generic that you could just add to a select component.

Anyway, [clears throat] latest isn't a thing anymore. You need

the opposite. Every value is the equivalent of latest helper in this world. So, you might actually want the

world. So, you might actually want the opposite. A way of showing the proposed

opposite. A way of showing the proposed value before it's finally applied. Edit.

Spelt is proposing an eager helper to do this. Makes sense.

this. Makes sense.

Um, in in my solid examples I'm going to show today, I didn't really have a name for it. I call it pending. So you have

for it. I call it pending. So you have is pending and pending. One gets you the pending value. One asks if it is

pending value. One asks if it is pending. Same API works. You know,

pending. Same API works. You know,

pending also um is an expression. It's not you can go

an expression. It's not you can go pending procount. You know, it's it's

pending procount. You know, it's it's it's the same thing.

Can it be a third function in the well that's why I'm saying I because you're asking about the graph not about async. You could be asking it about upper phrase which is derived from

phrase you know what I mean like this shouldn't be something that you put on the primitive itself. It's very

important because otherwise people will do weird things like wrap their async with other async so they can like get their hands on it or something like it's

yeah I mean yes but I mean it's a naming thing I I did I I tried I mentioned eager and people like that's weird and I'm like okay whatever. So I just called

it pending props account. We we have that as well. So there's is pending and pending, but it's pos possible that people think pending means true false.

Is it a pending value? So I'm I'm okay.

We can debate what to call it. I I

called it latest for a couple days. I

wasn't really sure what to call it, but yes, there is one that returns count and there's one that returns true,

but yes, it's the same idea. State

changes would apply async. Yes, React

behavior. Since derived values take time to propagate and you wouldn't want to witness torn state, it makes no sense to commit state immediately. More state

changes could occur before synchronous block ended that could cause async to entangle. So you could never know at the

entangle. So you could never know at the time of write that you commit it right away unless optimistic.

And I keep in mind I wrote this before I even had any idea if I could solve this.

This was just I love starting with an idea. But I did recognize that if you

idea. But I did recognize that if you weren't going to update state right away, Milo's R3 looks really interesting. And

for those who aren't familiar, I talked about this on stream a while ago uh Milo Pro reactively. Where's R3? It's funny.

Pro reactively. Where's R3? It's funny.

All his commits are probably on R3, but Oh, he's doing some dev tool work. Where

where is R3?

Pause it backtory R3 19 hours ago.

Optimistic is I want to be optimistic is different. Um optimistic is state that

different. Um optimistic is state that doesn't exist. Like in React these days

doesn't exist. Like in React these days they're using it for all the cases. But

I I don't think I think we should keep optimistic to refer to stuff like when you it's not like it's like stuff that doesn't exist like you manufacture like when you're saying like add when you add

a to-do optimistic lets you add a new to-do to the list before you actually get the to-dos from the server where this is more of like if you change the tab

to from A to B a way of getting B even though you're still showing A optimistic as I said has a very very different like

purpose in terms of like it's it's not like hiding something that's under the hood. It's literally like it's the React

hood. It's literally like it's the React uses it for both but that's why in a lot of React examples you have to call set state twice. you're like set pending

state twice. you're like set pending true and set whatever, right? Like you have to set both you sometimes like you end up setting doing double setters where here

you don't actually have to do double setter.

You could use optimistic. I'm not

getting rid of optimistic, but you almost just don't need it for these basic data fetching cases. It's you

probably only need optimistic when you're actually performing actions.

Oh yeah, good question about errors.

Yeah. Um,

state updates aren't really rolled back.

If Yeah, it's about eventual feature. If

something errors, the new state is shown with the error boundary. But don't you roll back the signals? No.

Like if you change to tab two and fetching two fails, you just show tab two with an error, not roll back to tab one. Yes.

one. Yes.

optimistic state gets rolled back. Yes.

Yes. That's the that's the difference.

Okay. So, if if we're if we're going all in and we're not going to do updates right away. I I rejected R3 originally

right away. I I rejected R3 originally because it's eager like solid is today and we're all lazy. But the funny thing is while I

all lazy. But the funny thing is while I was working through solid 2.0 like 90% of the stuff was eager anyways. Um but

what inspired this was modern single implication Jasc implemented using pushpull push tryoling. However, this

approach requires overeager marking of all recursive dependency making impossible to be an 01 implementation of create selector create projection like things that project like uh do um

derived granular updates um which marking only a subset of the children based on the return value of a computation. This library implements a

computation. This library implements a different approach to activity using topological execution height ordering to allow for nodes to dynamically change sorts of the heights. We fall back push pull push algorithm. Okay, but I'll

explain what that means in a second. But

essentially what this means is he he's created an O to the one reactivity algorithm which I I benchmarked it. I

mean it's similar to alien signals on most tests and actually faster in it than others. He might have created the

than others. He might have created the fastest reactivity system to date, but it didn't fit our use case. So I kind of rejected it.

Yes. Uh I already have examples with optimistic uh the to-dos example that I was showing earlier here. I mean this one's in react but yes

here. I mean this one's in react but yes I I have a version of it.

Collections solitude experiments. No,

not that one. Collections

yan singles talk async to complete. What

you're going to see actually is an optimistic store, which is really a cool little thing because I was able to take the same logic I had in the original store and make an optimistic store. And

then the way this works is it's derived from the async data. So whenever the server refreshes the data, it just automatically does a reconcile dip on the store on the optimistic store here because this is actually a projection

with the readr um because this is a function. I I'm I'm kind of hiding it.

function. I I'm I'm kind of hiding it.

But in the same way that we can do derived signals, we can do derived stores that are projections under the hood. So this is actually this

hood. So this is actually this technically speaking. So um and I made

technically speaking. So um and I made it so that um diffing is the automatic default for returning data. Uh if you want to do

returning data. Uh if you want to do mutation you don't diff anyway. Um so

then basically you have create async and then you have the store which is writable. So for ephemeral here changes

writable. So for ephemeral here changes it tries to do these changes. If the if it fails then it will not apply them and it'll you know you can like the

transition like basically it these always reset back to the base value. So

if it fails your div refresh won't have the new data which means that it will be diffed out of the final solution but if it passes the diff won't find any changes and therefore do no additional

work. Um but the optimistic state

work. Um but the optimistic state generally gets reset back to what it's derived from um at the end. And in the meanwhile you can do fine grained

updates like push or filter or update one of the to-dos. So you get fine grain updates on the optimistic state um and then diff on the way back that hopefully matches the optimistic

updates and no changes. This is like how you do the Strello demo um with minimal code.

Yeah, you missed that part. I It's for actions that we could have a different API, but generators are you either have to use a generator to reintroduce the

transition context or you need to um have async context. We talked about this earlier in the stream and I talked about in previous streams as well.

Yeah, it's it's just it's one of those nastiness in React. Right now you call transition and then you call transition again to wrap the data refresh. Um it's

just we can build APIs on top of this like the current query and action APIs in the router. So developers don't need to

router. So developers don't need to worry about that. And this after the await literally happens inside the logic of the router action you know with the server functions doing the validation

automatically. But this is the low-level

automatically. But this is the low-level API which is really cool because it's generic. It literally works by basis. If

generic. It literally works by basis. If

you were to build a nicer wrapper over this, it's it's literally this code. Way

simpler than what we have to do today.

It's just part of the basic um system.

Okay, sorry. Um got tangented a little bit. Um I want to talk about R3 for a

bit. Um I want to talk about R3 for a bit. Uh

bit. Uh just a just a second here just so you can understand what's going on here because um

I mean I did talk about it a little bit before if you see this from the stream.

I was talking about um one of the challenges I hit because I did talk about this article last stream. Um but

essentially with a pushpull system when you write to the signal you have to notify and then when you access a pure computation on demand it'll calculate the value or it'll basically run everything when it's when it's running

the scheduled side effects. It'll pull

at which point it will calculate the value. In React, you call set state,

value. In React, you call set state, nothing applies, and then you commit the state and do the pure computations um at

and the at the same schedule time you do the side effects, it's scheduled and R3 is kind of the same where you they don't have to notify up front because it's a

single pass algorithm. Um which means that um it can basically just do this in a single um run, which is really interesting. You might be asking

interesting. You might be asking yourself like, how the hell does it do this? And

this? And yes, it's funny. We talked about a lot of this stuff before. Um,

did I actually talk about I'm actually kind of interesting if I talked about if I talked about R3 before. Let me see

if I can zoom any further out.

No no no.

No, it doesn't look like I've talked about R3. Interesting. I wanted to have

about R3. Interesting. I wanted to have Milo on and talk about R3, but it's kind of kind of interesting. The the gist of of R3 is it uses height ordering. So

whenever you create a dependency, your your height becomes so like as you create the the graph, your height becomes one plus your dependency. So it

just as it runs the the the function it goes okay this dependency is level one this is level two level three and then it goes okay so my biggest dependency is level three I must be level four and

then when you go to insert instead of it just being like uh pushed to the end of an array you actually put it in at the height so stuff tends to run in the order that it was like created in from a

dependency standpoint now obviously with dynamic dependencies it's possible for stuff to get out of whatever. But what

Milo realized is if you ever come across um a value that has a height that is um lower than your height, like so if

you're level four and you you hit an if statement and you read a level six, well, and then you're like, "Oh crap, um this hasn't been processed yet."

All you need to do is mark the nodes from from your current height because you've already run through everything like you you've already run through level one, level

two, level three, you know, you're on four. You can just mark the remaining

four. You can just mark the remaining nodes that are already queued in the heap with the classic pushpull algorithm and then color them and then then you go

six are you dirty? like so you can fall back and then once it's finished and it goes six goes oh um yeah I am dirty in fact so I do need to recalculate my

value then you are no longer four you're now seven and the next time you run you'll be seven and even if that dependency changes and um there's no

more six like three is your highest dependency you'll still run at seven it doesn't really matter as long as you run after your dependencies so it's it's kind of a clever way that it deops in

the specific case one time in order to make sure that stuff's up to date with the marking like so at worst it it's basically like worst case it works like

alien signals but best case it can work better um so like it's very very cool approach but the downside is because it's lazy you can't just ask a value any time you could but then you'd have to

recmp compute the whole heap graph which to be fair is not that different than what solid does today when we you call set state and we just run the whole thing But um

you can understand why it starts looking more appealing in a world where um where your like react and your state changes are in the past because then you

don't have to sorry this is a good time to show that Excel draw then you don't have to worry about about this. There's

a second reason why this is really attractive and that is the way we do transitions today is cloning. We clone

the reactor graph. You can think of it like get. We literally go I I I think I

like get. We literally go I I I think I tried to maybe not in here. Yeah, it

wasn't on stream. I didn't do it. It

doesn't matter. I tried to to like show what this looked like. I think Dev tried to show what this looked like. It's it's

very hard to show in space. I think I wrote an article explaining how to solve transitions that I covered on stream before. I showed like cloning part of

before. I showed like cloning part of the graph and like committing it back in like get and that's expensive. Can you picture if

that's expensive. Can you picture if every time you set state you had to clone the clone the graph especially when you have to consider like we make real DOM nodes not just

virtual DOM nodes it would be very expensive um like the we don't have to clone the cloning doesn't make new DOM nodes the rerun does so that's like not exactly

fair but if if every time you set state you're going to have that overhead of cloning and then merging it back in like it's okay when it's like isolated to a transition but literally every operation

would be had um it'd be expensive. I

mean, JS framework benchmark, I think there's a version in here of React with transitions, which again is completely useless in this example. It's

literally just a run through, but if we go transitions, React cooks with transitions 1.93. Like

we're talking like not quite knockout in this example.

Where what are we looking at? Like

uh incremental DOM. Is there anyone else in this? Are we are we No, we're better

in this? Are we are we No, we're better than Ember. But yeah, Ember is here.

than Ember. But yeah, Ember is here.

Knockout's there.

Like this is not a happy place to be when you consider that React itself is the why.

That's so funny. Why can't I scroll?

Okay, React itself is um should be ahead of React, right? React

say faster than React.

React.

Where is React?

Oh, yeah. No, I'm still seeing React libraries.

Yeah, React hooks is over here.

Yeah, React classes. Yeah, base level React is here.

Hand optimized. I say base, but hand optimized. The compiler is right here,

optimized. The compiler is right here, basically beside it. Basically the same speed. Compiler hooks right here. Yeah,

speed. Compiler hooks right here. Yeah,

it's like 01.

Add transitions needlessly on every operation and you're like way off the deep end. Like it's not what you want to

deep end. Like it's not what you want to do.

So how do you add transitions essentially without paying the cost because you don't want to fork right and this is the challenge if you notify you have to fork at that

point because you have a different state you you're basically like I mean maybe there's a way you don't have to fork but that's the point at which in my transition thing I forked because at that point the nodes are

entering a new state they know that hey I need to be updated reality you don't want you don't want them merged Because like what if something that's not in the transition updates and then you know

like then it's like in the wrong state or what if something outside the transition sees that it updates and tries to recalculate and it calculates without the transition value in mind and

then clears that state and then the next thing the transition sees and it doesn't see it. Like you this is when you fork.

see it. Like you this is when you fork.

Whereas if you have something that doesn't notify, you can basically defer forking until

you when you actually run the thing, right?

Brain hurts. Sorry.

[sighs] Yeah. Height is how many times?

No, it's the height. So, it's it's it's like um it's like we could pick a graph shape.

Maybe this is the one where I did it before.

Let's pick a graph shape. Yeah, here we go. I did talk about this is it. This is

go. I did talk about this is it. This is

it right here. Height zero, height one, height one, height two, height three.

It's based on the shape of the graph.

your height is always one plus um thing you depend on at least. So like it's possible when this starts at zero when this one gets created it goes okay I'm

bigger than this I'm one this one gets created let's say and then it goes I'm bigger than one it becomes two but as it's like I guess that wouldn't be the order when you when you do creation

order you you you don't run three before two anyway so creation order almost always works like because generally um you you like you might have created

these out of order And these might be created in a different order than this, but you're not going to run this one until you have both depths, right? So

that's actually fairly straightforward, but it like this could be create signal, this could be memo, this could be memo, this could be memo, this could be an effect that reads from both of these.

That's what I mean by height order.

Does that does that make more sense?

And then in the future when you cue it, you you cue this at zero, you cue these at one, you cue this at two, and you ceue this at three. And then when you run through the graph, you run it in

this order. 0 1 1 2 3.

this order. 0 1 1 2 3.

And you did this all without having to do like a multiolors thing like a Yeah. Like if you've ever seen uh

Yeah. Like if you've ever seen uh supercharging reactive performance, which is Milo's article.

Um, go away. Um, oh, right. I forgot the stupid images all disappeared. I got to remember Milo, which is unfortunate.

This is the only one that's still here.

But like this coloration algorithm where it kind of walks through and figures out what has changed or could have changed.

Generally it starts with you do an update and you flicker everything like these red and these green as in these have definitely changed these might have

changed and then as you walk through you kind of flicker the state but you end up like if you notify everything like this and then you cue the effects

and you do it lazy from poll you actually start I mean I don't have all the images here but you actually start from the bottom essentially and then you

go you go okay am I dirty Maybe. Am I?

Check E. Am I dirty? Maybe. Check C.

Definitely dirty. Run C, which causes E to run.

And then F continues on, sees D. Or no,

now F knows that it's dirty. So F starts running. Um, and it's got it's got E and

running. Um, and it's got it's got E and then it sees D and then D is like, "Oh, I don't know if I'm dirty, but I could

be." Checks B. B runs, then D runs, and

be." Checks B. B runs, then D runs, and then F runs. That's the state-of-the-art in signals frameworks these days. That's

not how Solid 1.0 goes works. Solid 1.0

was really simple. You literally just push these all on a stack, run these ones before the effect at the end. You

just push it. It was always eager. These

were always scheduled. So, in a sense, R3 is a return to Solid 1.0's simplicity in terms of propagation. Um, but it's smarter. So, like it doesn't like in

smarter. So, like it doesn't like in solid 1.0 it was possible.

My my little baby has just managed to open the office door. I have no clue how he did it.

>> You didn't close it all.

>> Okay.

Very impressive, Luka. Daddy, very proud of you.

Okay. Um,

you can find the complete model on Do you have the link for that? Uh, let's

see. Milo, I guess you can't post it on uh YouTube. Milo

uh YouTube. Milo MG blog because I actually don't know one boat project.

Oh yeah, nice. He has all the images here. Okay, this is the version that we

here. Okay, this is the version that we should be using from now on.

Luka did a little set open true there.

Yeah, I have no clue. Oh, he got in, but he's crawling around now.

Well, let's Yeah, you are jumping ahead a little bit. Let's Let's look at what I realized. Um I It just R3 seems more

realized. Um I It just R3 seems more more attractive now in in this kind of world where you can, you know.

Um anyway, uh let's continue.

So like because you don't have to flush early. That's that's basically the

early. That's that's basically the thing. Um and then

thing. Um and then actions need to be different. Blah blah

blah.

I talk about deferred set signal and saying how everyone would hate it. and

is pending is a good idea and we should do that. That's where I left it last

do that. That's where I left it last stream and I kind of walked away and I was like whatever, right? And then I had

the uh a kind of breakthrough um like a it occurred to me that we could just take a completely different approach.

Now I've shared this article on Twitter, but I want to cover it on stream here.

Um, no. Um, he's literally working on

no. Um, he's literally working on something right now. He's kind of disilling it to the world.

Yeah. I mean, is it true that the overhead push pull thing is sometimes more simply than pushing? Yes. Uh, it

would be right. Um, you know what? Maybe

this is a good time to take a quick side tangent before we go into this. Um um

because No, no. Well, let's finish this thought

No, no. Well, let's finish this thought and then we'll Yeah, I I want to watch Joseph's talk on stream and talk about it a bit. Um which is completely

relevant to this. Um

but yes, the pushpull ultimately reduces the amount of work on the end. So it reduces like the user code. Um essentially it

means that less user code runs which it makes a lot of sense, right? Cuz like

everyone, you know, you hear people complain and they're all, you know, they're always like talking about React and performance and stuff and and uh and uh and like

I I think it's kind of funny because like the React team's like, "Oh, this kind of performance, framework performance doesn't matter. It's your

end user code that bogs you down." Well,

it's actually pushpull is what reduces the end user code that actually runs.

The React compiler does it as well, but I want to point out that but the cost of the push pull isn't that expensive. But

if you do like an very myopic like like the JS reactivity benchmark, you're probably going to see the cost of that push pull like where you there's no load on the end, no actual work, and you're just measuring how fast reactivity

propagates. Something that propagates

propagates. Something that propagates once through is going to propagate faster than something that basically does two and a half. Um, so

compared to any actual work on the end, this is why I usually ignore those benchmarks. Um, obviously

benchmarks. Um, obviously there's like a nice benefit to knowing that your system's generally simpler and faster. Um, but

faster. Um, but it doesn't matter. The the reactivity benchmarks don't matter nearly as much as the JS framework benchmark or and even that has like a limited scope of

use.

The problem is if you don't do it smart push like push without having this kind of smartness in terms of or scheduling like signals do like like RxJS or events

can lead to tons of wasted work at the end. Tons of wasted work because they

end. Tons of wasted work because they like create cycles and you know diamond problem and all all that kind of stuff.

So like you if there's definite benefits to push pull over push um in terms of like making sure because

it's like it's push knows what's updated but doesn't know doesn't know what you care about.

Pull knows what you care about but has no clue what's updated. Right? So like

you these are the two extremes right?

Like if you have RxJS and you push out these things, you have no clue if you're going to need all that. You're going to recalculate everything and then find out that you might not need everything. Um

and and this is the danger of a of a pushbased system. Uh if if it like

pushbased system. Uh if if it like doesn't know that it needs stuff, this is why we do like push pull. Pull like

React has no clue what's updated. It has

to literally diff everything, right? it

knows that what you care about like the part that's in the view. So, a lot of the techniques that we've been working on is kind of combining that knowledge like using the knowledge of like what's

subscribed to in the graph um along with you know the kind of push pull thing.

Now you might be thinking well then doesn't R3 have this problem that push has of doing extra work and it does.

Technically speaking, you will calculate memos that might never be consumed like computing, which is the same as solid today. The thing is because we're

today. The thing is because we're focusing on UI graphs and context and ownership, it it doesn't actually matter that much

outside of like large global store type scenarios where you have lots of derived work. Um, so we were working on lazy

work. Um, so we were working on lazy memos obviously for that reason, but I think there's a better abstraction specifically for the lazy stuff be because with inside the components and

things you generally your components will render um um

like you you'll you'll create what you need as part of the hierarchy of the tree. So, like, yeah, don't get me

tree. So, like, yeah, don't get me wrong. I'm just saying on one hand, you

wrong. I'm just saying on one hand, you could be like, "Oh, yeah, lazy is way better, right? Because it doesn't do the

better, right? Because it doesn't do the extra work." But on the the other hand,

extra work." But on the the other hand, what you could say is that this is no worse than solid is today. In fact, it's better. So, like it's already an

better. So, like it's already an improvement. Maybe not as improved in

improvement. Maybe not as improved in one dimension. It It's already better

one dimension. It It's already better than what we do today.

R3 makes sure that that it runs in order so that those effects only run once.

That's the thing. The algorithm using height mapping of the dependencies informs it.

Right? So that that's that's the magic of this R3 um repo approach is it's they he

basically figured out how to use an 01 like propagation to get the guarantees of a pushbull system.

It's the only thing is it's it runs eager not lazy.

Yes. overhead of checking dirtiness of depth of the pull is often which is why React's common knowledge is like don't overuse memoization because the checks are actually more expensive than just

running in most cases. React compiler is pretty liberal in not applying memoization to a lot of like simple cases. It means you can miss some and

cases. It means you can miss some and you sometimes still have to use memo but generally speaking this is like why it's dangerous to

overuse memos.

Okay. So, R3 pretty cool. Um,

so this this I I was like, let's let's let's take a gamble. Let's build a future. I I was sitting there, not

future. I I was sitting there, not catching, should I? I I I just had a brainstorm, like an epiphany at one moment that I was like, I can do this without a compiler. I can like I can do

what spelt does without a compiler with react guarantees and and then I was like let's just pick up R3 and see if I can use it because R3 actually fits the pattern. I rejected R3 like not rejected but kind of pushed it

back like 4 months ago. I was like now's the time. Let's just build take R3 and

the time. Let's just build take R3 and build a new reactive system from scratch. I know it was brutal cuz I

scratch. I know it was brutal cuz I literally just put the stamp on and I was like about a month ago and I was like sweet I think we're done client side. I think we're ready to go to the

side. I think we're ready to go to the next phase of Solid 2.0. know alpha I have transitions working optimistic states everything seems to be good it seems to be bugged thanks everybody in the discord helping testing this is

ready to go forward and then you know I saw spelt I saw Ricky stuff and I was like and I was like

it occurred to me like I already knew we'd be have to defer the commits like the values but it occurred to me that we could defer disposal and this is this is the this is the crazy crazy part Um,

right.

I wanted to kind of show this so people can understand. I'm using solid um split

can understand. I'm using solid um split effects here to kind of show it, but but I mean this is actually talking about the problems. I don't know if I want to

get into the the the problems too much, but essentially the the core basis of it is any decision in a reactive framework like or at least

a pure reactive framework like an if statement is a memo. Um you you essentially uh

you essentially have like a I think actually I have no I didn't someone when I changed it that I actually updated it. Yeah I I don't have

that example at the moment so forget about it. But essentially it's a memo.

about it. But essentially it's a memo.

It's like a if condition go one branch and the other branch and and like I can I can draw it. Let's just go here. But

like at the very basis, a show component is is essentially like create memo.

Like you can kind of think of it like show is more complicated than this. But

like at the basis of show component is create memo return create memo um

if condition which what was like so show what was show it's uh show when yeah so if props

when like this is a way oversimplification But what I'm getting at um

props children call it as a function. Let's

pretend it actually. No, it doesn't need to be a function. Um

unttrack it looks like this.

Unttrack because you don't you don't want the children's like top level reads. So you want to keep component

reads. So you want to keep component rules working otherwise basically return

null. This is basically what a reactive

null. This is basically what a reactive decision looks like right and it's it's simple whenever when changes. Now you

might want to have a boole like what we do in show is we actually make it so that like it's truthy because this would be like when two three four it would just keep on recreating this thing every

time. So technically it's more like it's

time. So technically it's more like it's more like cons and then you go like there's different modes but it's it it's

more like this because you want to isolate um equals create memo and then essentially

what This does is whenever props changes, it checks its truthiness and only if it changes from true or false, then it will trigger this memo, which

then will rerender the children. Okay,

so there there's a show component. Yeah,

whatever. I don't Our show component doesn't have props. Right now, I mean, you're right. It takes two seconds to

you're right. It takes two seconds to add props fallback and trash props fallback. Okay, there we go. We we added

fallback. Okay, there we go. We we added we added um a fallback to our component.

There we go. Sweet. So now we've just built the show component from scratch.

Now that's that's the gist of it. Um

the challenge is the way that Solid works is it has automatic disposal.

The the problem is people we don't know the answers until we try.

I I don't know what how else to to put it.

I think it's better to do the work up front and make decisions on that and be open about it than than to release something and then change our mind

every, you know, couple months, right?

Solid 1.0 has been stable for years because I spent this kind of work up front before I released it.

Solid start took a while because we spent the work to make sure the right patterns. I'm convinced on those compat

patterns. I'm convinced on those compat patterns by the time I was at the end.

We we we waited longer and look what happened. Now it's both spelt kit and

happened. Now it's both spelt kit and tan stackar basically almost straight up adopted our patterns. Like sure there's some syntax differences but we we we

arrived at the right place.

Sometimes the stuff takes time and that's just the reality of it.

you can call it a research project but there is definitely research involved right like I I don't know how how else to to to

explain it how like right hopefully the next we will have faster majors after this because the way we're reorganizing and stuff going but um I'm I want to be confident on the

foundations we set here for this is like our React 15 React 16 moment, you know, where we have to decide the fate. This

this is the last time we get to kind of like even though the APIs probably aren't that breaking, but this last time there's a few I this is the last time we

really get to I think things just go up from here. Um

people feel I feel like people want a major version increase yet sassive when they're breaking. I mean what can you do

they're breaking. I mean what can you do right? I mean they keep on using solid

right? I mean they keep on using solid yeah 1.0 for a long time.

Yes.

And the funniest thing is this has been going full circle. I don't know if you guys are picking up on this. I I haven't talked about the solution yet, but both the eager reactivity and the the way

that I do transitions are more like solid 1.0 than the stuff that I've been doing on 2.0 the last year. It's it's

actually kind of crazy how we've come full circle. Um we were right about a

full circle. Um we were right about a lot of the stuff in 1.0.

Anyway, my point here of showing this simple control flow um thing, you get why this is here. is the force true or false so that like when it stays true it

doesn't cause it to undo. The the

challenge is inside this proc you're going to create other signals and memos and stuff or fall back. And the way solid manages everything so wonderfully is whenever this function reruns

we discard of everything in in between like what will happen is this memo will get sent into a render effect somewhere that will actually insert it in the DOM

down the line. But essentially you don't want this to rerun unless this changes from true or false. You

don't want you know like stuff inside can change. You can like change data but

can change. You can like change data but you don't want to rerender the whole branch just because count went from one to two unless you do like sometimes like that's what a keyed update is, right?

But but like for the most part and I want to bring this up because every time this runs it throws away the old stuff.

which is the whole problem, right? If if

now this is showing a switch between tab one and tab two, tab one, tab two, right? Pretend it's not showing

right? Pretend it's not showing fallback. We're tab one and tab two, we

fallback. We're tab one and tab two, we have we have a problem because the second we switch to tab two to look at and fetch our data,

we threw away tab one.

And then it occurred to me. I'm like,

what what if we didn't what if we didn't throw away tab one? In in theory, memos are pure computations, right? Do

do you get what I'm saying? Like these

these don't have side effects. Like yes,

it might build a bunch of DOM nodes. It

might um it might do a bunch of you know work inside its own scope but it's it's over here where you're like create render

effect where you read the results of this show you know whatever show component I'm just doing this for whatever

purposes when you get back whatever the children is it's in here on the on the other side of the effect here when you're like children you know whatever they are that you do the actual like

insert work where you're actually like you know parent you know children [clears throat] you know do whatever stuff this is where

all the work actually happens down here.

So the and it occurred to me that if as long as you know

it it probably doesn't matter that we dispose this right away. That was my thinking, right? [clears throat] Because

thinking, right? [clears throat] Because you use an effect like like when you want to make a side effect in the DOM and in the new uh solid um API for

create effect um where you have your dabs and then you have your callback function, you can do the good old React return

cleanup, right? And you clean up your

cleanup, right? And you clean up your stuff right?

you actually get depths back through here the way we're doing it. But what what the the point that I'm trying to make with this is that like um

this is where your side effects happen, right? On mount fact, this is where

right? On mount fact, this is where you're doing most your work. Yes, there

is technically an on cleanup that can run in here, but the what if we don't dispose of this right away,

it's possible that we can have both realities existing at the same time. Earliest version

transitions in solid should go I have like a medium article on this stuff like mediumcom solidjs.

See uh maybe I should just go to my medium page. Let me see if I I've been working

page. Let me see if I I've been working on these problems for long time. Um

where's my stories? my stories. Is this

just like a fake thing where they like Okay, got it. Yeah, thank you. Oh,

actually, I didn't get it. What did it say? Did it tell me that they moved it?

say? Did it tell me that they moved it?

Yeah, they they did move it. Okay.

Uh where was it? Designing SolidJS

substraction. Designing SolidJS.

One of these designing SolidJS suspense.

When did I write this article? Sorry,

just December 3rd, 2019. Okay.

Concurrent mode. Okay.

I showing suspense off here. Okay.

Transitions. How did I do transitions back in 2019?

Use transition. Okay.

Oh, yeah. I did it.

Okay. So,

yeah. You know what? Maybe I updated this article.

This looks like it's already up to date.

Yeah. Suspense list. Okay, never mind. I

I had an earlier version before the 2019 version that apparently works perfectly fine.

Crazy. Um I didn't realize I did it that early. Um

early. Um never mind. Uh which which actually

never mind. Uh which which actually hijack your control flow and you'd pass a transition as an argument into the control flow component so that it could actually just opt into this behavior.

But the gist of what I'm trying to get out of here is that the the the idea is what if instead of disposing what's on the page,

you keep it around and if you detect by the end of this update that there's async involved like that it's a transition essentially.

Well then we don't throw it away and we keep it around and we keep on updating it. But

if we get to the end and there's no async involved and it's not a transition, we just dispose of it then.

And basically we don't fork anything.

We just defer disposal. So we don't create anything new that we didn't need to create. If you're doing an update

to create. If you're doing an update from condition one to condition two, you're definitely going to, you know, tab A to tab B, you're definitely going to create tab B, you know,

but so it's not like we're wasting work.

We're just upping the memory temporarily a little longer. So instead of releasing A right away and then creating B, um we we keep A and B around simultaneously

synchronously till the end of the flush.

Now to be fair, synchronously I don't even know if GC would even have time to operate. Like this might not even be a

operate. Like this might not even be a noticeable overhead. We still need the

noticeable overhead. We still need the benchmarker, but I did benchmark this in the reactivity benchmark and it had almost no it had minimal overhead over R3. It basically brought R3 back up to

R3. It basically brought R3 back up to alien signals levels in terms of performance. Like we we actually didn't

performance. Like we we actually didn't get hit. Now, I'm sure the performance

get hit. Now, I'm sure the performance would degrade a little bit further as I add more solid features on top. Just

kind of how it is, but the reality was this is the fastest version of the reactivity that I've ever worked with.

Um, even with this behavior built in now, they're not testing this behavior in the on the in the reactivity demo.

They don't even have ownership. They

don't even have depth. So like I don't know of the cost of this but the important part is for people not using these features it's you're not paying a

penalty. You're it's the fact that it's

penalty. You're it's the fact that it's transitions everywhere doesn't have a performance overhead. This was the

performance overhead. This was the critical why would you want to keep a around right here

so that a is still working. any of the go. It's so that when you go to tab B

go. It's so that when you go to tab B here and fetch in the background that A is still live. It's the holding behavior that we were talking about. See how this counter is still going. If we just released it, we might be able to do

something smart where we like left it on the screen, but this counter would stop.

This is why I use this demo in every example. This is a live part of the

example. This is a live part of the graph while this async is applied. Now,

not everything's a tab switch, so to speak. This is a more general concept,

speak. This is a more general concept, but um I wanted to which yeah, sorry. Yeah, I can save this. I I

yeah, sorry. Yeah, I can save this. I I

just wanted to kind of show this as an example. Let's see. Can I increase the

example. Let's see. Can I increase the delay here? Let's go plus 380. Yeah,

delay here? Let's go plus 380. Yeah,

let's do this.

See, it's so that these are both existing in time. It's basically a transition, but there's no transition.

There's no forking. It's just the fact that we use a combination of keeping the values in the past and deferring pure disposal i.e. non-sside effectful

disposal i.e. non-sside effectful

disposal that we essentially accomplish transitions as with no extra cost.

Still a few minutes do the research.

Make sure you're absolutely convinced you're happy with our design. Much

better than delay and get it right in the first time. Yeah.

So then you can switch to children without rerunning the call back again.

Well, the thing is if there was no transition involved, you would be switching like do you know what I mean?

Like if you're going from A to B, like you're definitely going to go to B and render something differently. Like

that part never changes. You're going to run A once and you're going to run B once. But

once. But you're going to have it run A and then when you switch to B, you're going to run B again. But what what's cool about about this approach is we can have them

both existing in parallel while that transit transition's happening so to speak.

And we didn't need to fork it. Like

before the problem was I would keep A where it is and then fork it and then test it out on B and then merge it back in. This is way simpler. I in fact I

in. This is way simpler. I in fact I don't have all the features in but solid signals implementation was getting to about 2100 lines of code built and yeah I don't have all the features in the

current one it's about 900 I' I have like half the size of the code complexity with this new approach even though the reactive system with R3 is probably like a tiny bit bigger but yeah

in the sync case the disposal happens after creating the next state of UI traditionally it would be happen before yeah exactly we defer so it's more like if If you view, there's a bunch of cues.

There's a pure Q and then there's like a render effect Q and this user effect Q.

1 2 3. Usually, as you run, we do clean up. So, you hit a node, you go clean it

up. So, you hit a node, you go clean it up, run it again, clean it up, run it again, clean it up, run it again. What

this does, it goes run all the pure Q, collect all the cleanups, then it goes, okay, I know because we've split the effects, we know if we hit all the async at this point, we run all the front halves, we run all the pure cues, then

we're like, okay, now, yeah, this is a transition. Then we go, okay, don't

transition. Then we go, okay, don't dispose of that stuff. Let's keep it around and keep it going until that transition ends. But it it gets the end

transition ends. But it it gets the end in there's like, no, no async. We're not

a transition. Whatever. It just disposes it at that point and then runs the render effects and continues on.

Couldn't the counter be in a global?

Yeah, but it doesn't matter if it's in global state if you're rendering it inside the component because if you

release it, you're releasing the reactivity. like it just it like

reactivity. like it just it like even if I keep a reference to it if I if I if I create a me it's the way solid works is when you because you you want

automatic disposal right if I create a memo inside a memo you know you're going to create a new memo so there's no point keeping this memo around you have a memory leak this is the classic problem with these reactive systems is they

leaky observer problem uh if the if the thing they subscribe to lasts significantly longer than its own life cycle, it stays there connected to that signal in the global scope. So what we

do is we register any children with the parent. So when the parent reruns it

parent. So when the parent reruns it disposes them automatically. There's

ways you can get around that like we use inside four components and control flow like for like control flow because we can release a row at a time but generally speaking the base behavior is

you just release it. Um, so even if you have the signal in global state and you're you release it, but you're still like just pulling there because you haven't inserted it yet, it's going to

not update because you the memo has been released. It's no

longer connected to the signal.

Yes, although I'm going to the technical side.

Uh let me get to the actual examples.

You might you feel sorry what behavior is unwanted.

Sorry I'm not quite following like the the the ownership model of automatic removal is just it's a base thing otherwise you could create tons and tons of memory leaks right like it's

literally well keeping the state around. I mean

the question is do you believe that like do you believe that or you just

mean like keeping the page live while the other page is loading? I mean, it's really, you know, the tabs going away.

So, like it being live is kind of like a like who cares maybe moment, but there's cases where you're doing mutations on screen itself where the whole tab isn't

going away or part of it is going away or like you know like things are changing. you you don't want the UI to

changing. you you don't want the UI to suddenly to freeze up momentarily because you're doing this action necessarily like you know what I mean like animations or other kind of stuff like the idea is to keep both things

live um that's the whole idea with the whole transition thing in the first place right two branches that that's the whole thing the whole time right

it might be notable if there's a reference outside being mutated inside cleaning up yeah if It's not pure, then you have a problem. It's like the React strict mode problem. See, the funniest thing is so many parallels here. React

is like if you just follow the chain inside our create memos. Almost all the things that React realized that it needed are true about the reactivity graph. We're like just one dimension

graph. We're like just one dimension outside. We we've we have our reactivity

outside. We we've we have our reactivity running through the component system.

We're React the component system is the reactivity. But conceptually, it's the

reactivity. But conceptually, it's the same thing, right? They throw they throw their components. They throw their UI.

their components. They throw their UI.

We throw we throw along a data graph that runs through our UI. This lets us run the UI once, which is incredibly powerful in terms of performance and in terms of like just like okay, there's a

thing, but the actual behaviors of the graph are very very similar to what React is in certain thing. We just have a world that lives outside the components which they don't.

Yeah. Well, no. Effects are fine.

Effects are fine. The effect cleanup is going to happen in order. It's only the pure side that matters. Effects are

fine. It's only inside memos.

Effects will run one, two, one, two, one, two, one, one, one, two. It's just

on the it's we defer pure disposal because the effect the part that I haven't showed is the secret part is the effect can read the render effects read

the old values. See normal effects read the updated value and they throw and they get caught up and they and they they don't update. Render effects

can read the old values. So they might run because like what happens if you in the same like they might need to run um

with like while something's holding and something's updating like that counter they might need to run at the same time where you have both pending value and non-pending value. So render effects

non-pending value. So render effects actually they don't they kind of tear in a different sense the word tearing. Um, so it's the UI

that does like the actual like holding of values in the past in a sense even though it's like represented as in the effect.

I believe the problem I believe there are ways to keep the counter alive but still cannot get problem with return clean up. There

there's no problem with return cleanup.

The return cleanup here is fine. This is

perfectly fine because it's in an effect. You do the side effect. I'm

effect. You do the side effect. I'm

saying that if someone inside here was doing on cleanup like inside this memo if you keep it around it's possible like this won't run

right away. This is fine. Your effects

right away. This is fine. Your effects

you most developers put their cleanups in effects or they should be or on mount or like like And even if your cleanup's here and it's

just temporary delayed, it's probably not a huge deal. Do you know what I mean? Like

mean? Like usually when it's a resource subscription thing, it's happening here, not here.

Yeah. Well, that's what I'm getting at.

Memos are pure, right? Like that's what the assumption is of this system.

You know, that memos are pure, which they've kind of been this whole time, right? It's the

reason Solid One has create computed. I

don't didn't want people writing to state inside create memo. We haven't

enforced as much as we could, but we literally gave people a primitive for it so that they wouldn't use memos like that.

Of course, they can use use effect as or create effect as well, but my my point is this deferred disposal doesn't actually cause

any extra work to happen. You're not

forking. It just it is a it just chang this change of timing on the pure part essentially allows for us to avoid

forking and my guess is that spelt kind of does the same thing because their control flow is special. They probably

associate with the blocks and defer disposal until the async resolved on the blocks. This is happening at purely a

blocks. This is happening at purely a reactive level. That was my idea. I was

reactive level. That was my idea. I was

like what if I could do this literally in the reactive system? Now, it's tricky because you have to cue them separately because if you cue if you take the pending nodes and you just stick them in

the normal queue and the you don't always want to run the pending node.

Like I had this problem where the thing overran like I had a test in in the repo where it was like it ran the inside one one time too many because on that last time you don't want to you want to

dispose and not run the pending ones.

But [snorts] I realized if I mark disposal and isolated queuing, so you have a normal queue and the to be disposed Q, we could

basically manage this. Um, and then I just went through a bunch of different scenarios to think about how the merging would work. And

would work. And you know what?

I I my my my takeaway was that since this would work I would be able to mark our existing nodes and just give them pending values pending dispose and pending dispo and pending like children

dispose and in a sense it if anyone's seen solid's current implementation we have something called tv value that's very similar like where we just hold the transition this was like just like I realized that this approach is basically

solid 1.0's 0's transition algorithm just done cleaner around disposal so that it's actually guaranteed like it's actually systematic instead of like 1.0

transitions have bugs in them like if you get complicated where this approach systematically I can make sense of and explain doesn't have the same kind of level of bugs. It's not like like we if

you look at the disposal code in 1.0 it's crazy like you're like if you're a transition didn't do this and didn't do this. This logic is like much more clear

this. This logic is like much more clear that you just have a queue of the dispose with marked dispose nodes.

Anyway, um because I want to get to the examples here in a second. Um,

yeah, I think I ended up just codifying this stuff more over time, but um, yeah, you know what? I think this

article is actually newer than the Yeah.

Yeah.

Yeah. This article, I'm not going to get into too much. just talking about the fact that actions are still required. I

think that's beyond the scope cuz we're not covering actions today. I do want to pull up one more spelt playground though to play with cuz this is this this is the one where I realized that I'm like I don't want spelt behavior. So, let's

let's talk about it. The idea is what if you have two states? Like I couldn't figure out for the life of me how spelt entangled the transition, but it's so

obvious in hindsight because I was like it I I came up with three buttons and two states. one state triggers derived

two states. one state triggers derived and the other state has nothing to do with it and going to update right away.

So this like non-async value, if I just click it like a bunch of times, it just updates immediately. This async value,

updates immediately. This async value, if I click it, there's like a delay to when it updates, right? And if I do it together, it's a

right? And if I do it together, it's a delay to when they both update.

But what's interesting about this example is like when I press together and then press non async there's like an interesting jump where it goes from

like okay now they're 2020 now I hit them together okay which should be 2121 right but then I'm going to hit this one and it's what it's going to do is it's going to show 22

before the other one updates which is weird because in a sense you you you would think these were entangled, but spelt doesn't have the same idea of entanglement. It's weird

that you can like see the update from the together button press before together resolves. Um and

together resolves. Um and and and it occurred to me that it was so simple. They they weren't using the

simple. They they weren't using the reactive graph to make their decision completely. They were literally looking

completely. They were literally looking at the synchronous timing. Like I was like, what how do I know these go together? It's literally, sorry I keep

together? It's literally, sorry I keep on saying literally, but it's just the fact that in within the same event handler, same synchronous frame, that gets part of the transition, but it's not a transition because if I click this

10 times, you're going to see 10 updates on the screen. They don't entangle the same thing. You probably have to handle

same thing. You probably have to handle cancellation yourself, you know, which is something that you don't in React or Solid. So, I was like, okay,

Solid. So, I was like, okay, this is more complicated. Um, but it should be doable. So, let's let's that that that kind of realization here

in terms of of like these these behaviors led me to kind of the the solution space that we internally model something very similar

to a transition but externally you don't have the wrapper for it. So how does this look like? Okay, I I I know I've been going kind of deep here but let's

actually look at some actual examples now. Um,

now. Um, and I'm actually going to do them in the opposite order. I want to start with um

opposite order. I want to start with um the async holding example. Okay. And I'm

I'm going to clear out a few of these actually. Perfect. I have the felt one

actually. Perfect. I have the felt one right here.

Sorry. Actually, that's funny. I have

the salt one. I want my my version.

Leave. I want

this version.

Okay.

Now, this is the same example. I've done it with with um just handwritten no JSX because that's I haven't implemented the JSX, but I want you to notice that these

are kind of grouped together like they're part of the same effect like

like essentially the one the one the the multi was it the value and the and the result are part of the same effect. So

like there's this one actually doesn't that aspect doesn't matter. Um in the next example it'll matter. So actually

forget about that. But essentially if you look at the difference between these examples they're very similar. They have

derived a weight and we have create async but it's the same idea. You call

multiply on the thing. Every time you click the button you just go n plus one.

Okay. It is not um it's not like any kind of difference in terms of concept. It's just there's no transition and you go is pending N,

right? You can just ask that about the

right? You can just ask that about the value. So when I click this, it delays

value. So when I click this, it delays and you see the dot dot dot and then it shows the value like you expect. Even

though these all have random timers, they all get tied together. And what's

more interesting is if I click this four times, it only shows it when it's done.

Click it twice.

There's no jitter state. This is like React transitions. We're actually we're

React transitions. We're actually we're actually stabilizing them. Whereas in

this example, I click it a bunch of times, it does that. Right? So, this was kind of like

that. Right? So, this was kind of like the first behavior consideration, right?

So, this would be like the the base default, right? There's it's hard to see

default, right? There's it's hard to see this without seeing the JSX and I think it'll be easier when people see it. But

what this example is showing is with no transitions and just introducing async, we get the holding behavior and the entanglement automatically and the obviously the ability to ask the

question of is pending.

Deferred disposal allows not to kill some nodes. Yeah, it allows us to keep

some nodes. Yeah, it allows us to keep both branches live at the same time without forking them. It's kind of like the reverse.

And once you realize that you're working towards a single feature anyways, that transitions don't really roll back um then this is actually a fair assumption. You can basically do zero

assumption. You can basically do zero extra work, just defer some of the work and it actually just works. Um,

so what's cool about this isn't this is this basic example doesn't show very much, but it just gives it starts getting you an idea of like how the

behavior should be, right?

Next example.

Actually, I should probably share this example in the chat just in case anyone wants to check it out.

next example that I want to show here and kind of explain it. As I said, people feel free to ask questions as we go. But this parallel async example um

go. But this parallel async example um which I also made in spelt this one is important because what you're seeing here is there's a single render effect

that literally has all the stuff. It has

the ID that we're going to increment that we're going to use to fetch our data and it's going to have our data.

It's going to have a count, which is just literally a counter that's going off in the background. And then it's going to show pending like what what the ID we are fetching it looks like. And

then I have a second render effect which sets the div opacities while it's pending. Um, essentially again the u the

pending. Um, essentially again the u the UI itself is just setting ID, right?

We're literally just going ID plus one.

So there's no transition, no nothing.

This is just the base behavior. What

you're going to see here is as I click this, it's, you know, doing dot dot dot loading one, loading two. And if I click it twice, 3, four, five, six, and then

jump straight to six being loaded. So,

we have the ability to inspect what will happen before it happens as as well. So,

we have both capabilities of showing the loading while it's happening. And the

reason I show this example is because I can kick it four times without and it only drops in when it's done. And also I can have these running in parallel without impacting each other. So even

though these are entangling because the graph doesn't overlap there's actually no um like the these are independent updates. Now like obviously if I force

updates. Now like obviously if I force the graph to overlap like right now this is rendering two components data 1 data 2 right if I did the old let's make local state global state like I'm

pretending it's like a component like just hoist it up then obviously these are going to be the same thing right and then they're going to tie together right that doesn't take a genius to understand that

you know what I mean like that when I update these they're the same thing and they get entangled but it means that purely non-entangled async has the potential to run

independently, which I think is important in this model because if you can't, you know, if you're not going to be setting the transitions, you want it to be possible for people to to have multiple updates in flight on this on

the same thing, right? So like the what's spelt doesn't

right? So like the what's spelt doesn't have entanglement. So obviously parallel

have entanglement. So obviously parallel works but it does do 3 4 5 6

4 5 6 7 8 like um so yeah it's interesting. Yeah I I guess I can't do the global state example as easily.

Um, I'd have to pass it in as a prop.

Um, it doesn't really matter. I I I I I don't I I'm pretty sure salt will behave the same other than it doesn't like entangle the stuff. But generally

speaking, um, this is this was like very helpful to kind of understand this. And and this was actually the example that I was working with with Tener that he got excited with because he realized something when he looked at this. He was

like, "There's no transition here, right? It's just you you you build

right? It's just you you you build something and if you forget to put a loading indicator on it, you know,

it's funny because I actually have the pending data in here, but so there is a loading indicator, but like if you forget this stuff, it still works in a reasonable way. you just you know you

reasonable way. you just you know you it's almost like the language that's describing the the thing you're like okay wait it's working but it's it's delayed how do I show you know a loading

indicator ask for is pending you know like it's there's something very natural about just like the basic the base version the way

it works and then just being able to ask this information now obviously if if I do a console log here for this to perk.

You You know what you're going to get?

Um when I click on this, you're going to see zero even though one, right? Three. Now it's I click it

one, right? Three. Now it's I click it three times, you throw it one three times. Now of course if I do pending

times. Now of course if I do pending data ID then we will get all the numbers 1 2 3 4 right but

though it's starting at zero which is interesting so maybe I don't have that working quite perfectly yet. Oh, right.

It's because right now pending is deferred a micro task. I'm going to have to I'm going to have to look at my implementation again on that. Okay,

that's fine. It's because I I needed to to not entangle, but I I probably have a different solution to that. But anyways,

I I don't know if it's obvious to people how dope this is, so to speak. I because

the I mean it's really obvious like you got to pretend this is JSX and stuff but it's really obvious when you're literally just using the reactivity system and it just works like this like there's no transition there's like all

you're asking is is pending or get me the pending value. Otherwise you just use the graph like normal and it's and it's and it's just like it just works

like it I I I don't know. I I think this is really cool that there's no transition wrapper. There's no you like there's no

wrapper. There's no you like there's no uh like framework aspect here like this is your compile code you know some people like show me the compiled code this is your compile code there's no

compiler here this is this is literally I just made uh a component and then um just you know appended some div elements

together you know it's it's it's literally just the reactive system doing this by its very nature being async first.

Yeah, I mean in terms of splitting out the uh the depth is the same because it has the difference is this runs during the pure phase and this runs on the not pure phase which is important um because

you want to be able to know about your async dependencies and figure out how to handle stuff. Now you could compile it

handle stuff. Now you could compile it in you could but then you have other issues. Um you could define another

issues. Um you could define another block scope to tie async to that's not based on the reactivity react uh you know but then you need a way of identifying that like spelt does with

its compiler but yeah this is th those are the trade-offs unfortunately setting if once you have that ability

and it's hard to explain like or showcase like I think this is something where we like you you you ask someone to create an app

the way they think they would create it and the with using the tools they to do today and then I think Rick actually did this on learn with JSON and then you just delete like all the the problem is

this deletes so much of the code like to to create this exact behavior in in in you know a framework without the async

features requires considerably more like it's way way more complicated um compared to just like this I think The select example, Ryan Florence is going

to be it. Yeah. No, no suspense, no transitions. Yeah, exactly. I mean,

transitions. Yeah, exactly. I mean,

suspense is still important because right now I'm faking suspense.

Uh, sort of. I mean, you don't need suspense, but this like loading state I'm doing right now by literally how am I where's the dot dot loading the

initial one? I'm I'm I'm setting the

initial one? I'm I'm I'm setting the text content when I first build it.

Ideally, what you'd do is you'd have suspense around this and it would just handle the loading initially and then after that like you will never go back to suspense again because like the way

this works it just suspense will never trigger after the first go. It's just

it's it's because you're automatically in like that transition zone. But yes,

you suspense is not necessary arguably unless you're like streaming. Um I think it's still probably good thing but you can there's a difference. I'm I'm

thinking renaming the suspense component to loading component. We'll have error component and loading component very kind of clear thing like suspense is just for that initial load like when you don't have the data yet and then

after that you just ask the question you're like okay now that I've loaded your afordances are going to be like is is it pending that's basically the question you just put that everywhere.

So like you you view suspense as like uh how you lay out your page like where your loading indicators are like for initial load and then once you're doing stuff and you're doing all the small affordance work, you just use this pending everywhere and then you're

you're good to go. You know what I mean?

You don't have to worry about suspense.

It's never going to jump back on you. A

lot of people were worried about suspense and they never they never use solids features like async features cuz they're like, "Oh, suspense just keeps on ripping out under me." And then I'm like, "Oh, then you use a transition."

And they're like, "What's a transition?"

And then you're like, "Or you can use latest." And they're like, "Okay, screw.

latest." And they're like, "Okay, screw.

I'll just use latest, you know, which is kind of like almost like this pending value." And I was like, "Yeah, but then

value." And I was like, "Yeah, but then now you're like not leveraging any of this stuff. It just, you know, like

this stuff. It just, you know, like now they don't have to worry about this with this API and position.

Suspense will never yank out of you."

And like stuff will work. And if you want to show a loading indicator, you just show your loading indic or your pending indicator. You show a pending

pending indicator. You show a pending indicator.

Yes, you that's the thing you switching back you lose it. And to be fair, solid 1.0, solid 2.0, every version of transitions

that I've ever done, switching back loses it. I react switching back loses

loses it. I react switching back loses it too. Except it's a virtual DOM.

it too. Except it's a virtual DOM.

Switching back has never been like there's no cancellation. It's eventual

future. So if that eventual future switches back to if you go one place and then come back again you you you've moved through time. You basically what would happen if no transition was involved and you went to one place and

you went back to the same place you would recreate it. This is no different.

Yes. Not for going back to the old one.

Yeah, there's no like suspense doesn't go away. Like we still have suspense.

go away. Like we still have suspense.

Suspense lets us render stuff offcreen.

Like the thing with suspense is you um and this is like full tab swapping. Suspense when you're tab

swapping. Suspense when you're tab swapping is not going to make a difference. The thing what suspense lets

difference. The thing what suspense lets you do is like when it rips it out of the screen, it's still live and it comes back and it comes back again like and you don't throw it away in the middle.

But that's that's not this use case. We

never go back to suspense. So you never have that ripping case. Do you know what I mean? Like this is like going to a

I mean? Like this is like going to a whole different page even under suspense that would Yeah.

I was I do think the be very cool and better than previous solid 2.0 model.

Okay.

F doesn't do this. It never disposes the main branch. Yeah.

main branch. Yeah.

Yes. Yes. Yes. Yes. I mean to be fair in the JSX you're not writing that event dependency array. Um but yes. Um and it

dependency array. Um but yes. Um and it doesn't have to be a dependency array.

It could be dependency object. It

literally does it's it's I array is just the easiest way of accessing it through.

Um it's it's literally this is a function. It could be a single signal.

function. It could be a single signal.

It's just an expression. it the using array was just like the way like compiler actually uses an object I think and gives each one a unique key um and

then yeah like our JSX compiler but it doesn't it it's it's more it's less like we're using it like an array because we pass the value through but it's more

like a views uh watch what watch views watch watchers Watch question. New question, old

Watch question. New question, old question. This is the API port

question. This is the API port essentially. I said I never got anything

essentially. I said I never got anything from Vue. Here we go. Got it from Vue.

from Vue. Here we go. Got it from Vue.

There we go.

Honestly, it was just pure coincidence.

But see, you watch X as I sum this. Like

it is literally like you can make it making an array makes sense. The only

difference is we don't put we don't do this on thing where we put the array on the outside. I This drives me nuts. I I

the outside. I This drives me nuts. I I

know it can make it shorter sometimes when you have straight signals and stuff, but like honestly then you get into like more complicated cases. You

might as well just make it always accept a function because when you when you accept an array, you actually have to iterate over the array internally. It's

like slower. It's it's just there's just no point. But generally, it is just

no point. But generally, it is just watch which means that we also have to support the deep keyword um for stores which um has a lot of optimizations baked in. I spent a whole stream talking

baked in. I spent a whole stream talking about how I was working on that. Anyway,

yes, it's basically like views watch. It

doesn't have to be an array, but yeah, it's very similar to spelt's new model except it provides the guarantees thing.

I've been actually been showing spelt examples inside the solid one like like this like this is the the same example in spelt using state eager here I had to do something because I didn't have

pending I had to do eager not equal year but I mean it's it's fine uh but like the only difference is spelt the biggest difference is the way this this goes one

16 17 like I click it a bunch of times and it goes like this I mean this is such a minor thing perhaps but the the Other difference is um so like in the solid version when I do this what you're going to see is it's just going to load

in once. It has the same parallelism

in once. It has the same parallelism where I can do this one and this one at the same time but it's just going to when it's finished like eager is this thing at the end here that as I click it

you'll see count up 13 14 56 17 but it is very similar to self model except it has the same integment link guarantees that you find in react that

built before um and it doesn't require a compiler. This is as you can see I'm

compiler. This is as you can see I'm using a DOM here. There's no compiler involved. This is purely built into the

involved. This is purely built into the reactive system.

Yeah, you don't write v 0 v1 usually.

Usually people use objects and uh like a lot of time people do independent effects. Um to be fair I I was using v 0

effects. Um to be fair I I was using v 0 v1. Do you know what most people do in

v1. Do you know what most people do in these cases?

They just destructure and then they just do this.

Let's be what is this one? this one

count and then data and it's way more easy to read it. data ID not equal ending data

read it. data ID not equal ending data I did I be where I have a B somewhere still

anyway I sorry I to be fair this This is more of like what the yeah

this is mostly compiler output. I'm

literally writing vanilla code. And as I said, if people did stuff, usually you they would, you know, make an array

and destruct the array or make an object and do pd data, you know, you know what I mean? Like there's there's lots of

I mean? Like there's there's lots of ways to to do this. Don't don't get me wrong. I'm not like absolutely stoked

wrong. I'm not like absolutely stoked about the result of this, but I'm kind, you know.

Yeah. I Yeah. No, it's true. Um, this is one of those things where like [clears throat] it it and I made an on helper

so that you could put it on anyone, but it doesn't make sense on the pure side to have on as much. So like yeah, this

is a bit of full circle going here.

Yeah, I mean we're catching up. We could

also do a dependency object. Yeah. Yeah.

Or dstructuring. Yeah.

Well, in the ren Yeah. The way that effects work. Um. Yes. to basically uh

effects work. Um. Yes. to basically uh render effects are interesting because how am I updating the count right now

while it's while it's while it's loading like look count is right here I'm running this I'm clearly running this effect you know like console.log log

hey. If I put hey in here, what you're going to see is hey running over and over again. And

then when I click here, hey is still running.

It's that because we don't commit the values. We know that when we're not

values. We know that when we're not currently under the active transition so to speak that we can show the stale values for things that are think or that are like when we're under an active like

under the a flush that's actually been working on the async like which is usually really easy to detect after the fact because usually you're coming back in because some async resolved which means you can immediately be like oh this async resolved we're back in

transition mode you know before you get here right in the height graph. um

because you know then you can always sh use the latest values and most time when you're doing reactivity you can do the latest values. It's only when you

latest values. It's only when you encounter something that's part of a transition and you're not part of that transition that you show the old values.

Um when you're in a render effect every other place you always enter inside the inside the graph is always the latest values. So this is this is basically

values. So this is this is basically like the one exception is is to every rule is the render effect. So there is like a framework aspect, not framework but like a render UI aspect part that

make render effects special. But other

effects um like user effects don't get brought into this. They don't affect uh they don't affect um transitions. They don't affect suspense.

transitions. They don't affect suspense.

They don't really care. They're they're

just literally when their depths are stable, they run. They won't trigger suspense. They don't care about that.

suspense. They don't care about that.

They don't trigger error boundaries.

normal user effects are kind of independent of the rendering. So, um,

which I've shown in other examples is very very powerful thing because then you can like even though they won't run like they'll be held when they're off screen like if they haven't been

rendered on um they they won't be the the thing responsible for stopping things from being rendered to the screen.

We use objects actually because the it was better than using the array. So we

use objects with with uh with things and I might be destructuring. Yeah, I'm not sure.

Sorry. It's just funny. You can't like throw a rock two inches.

Um, yeah, they're they're relatively easy. I think they'll be easier in 2.0,

easy. I think they'll be easier in 2.0, too, because we were more aligning with HTML standards in terms of most of our conventions. But yeah, I mean,

conventions. But yeah, I mean, straightforward. I have my own opinion

straightforward. I have my own opinion on web components. You should watch just Google me and web components and you'll see Does this mean no generators or resume?

No. Uh for basic you you do need something for actions, right? What's cool about this is you can see is in any case in which you are updating like like these

pending things like where you're just like do doing the [clears throat] stuff for on the fetch side not on the post side you don't need optimistic you don't need transitions you don't need any of

these other mechanisms like you're literally just going hey am I waiting or not like that's the question you're asking when you're doing async there's the first question you're you're there's only two questions I actually covered in

my talk it's like can I render this and is it out of That's what like can I render this is suspense essentially or the loading component and is it out of date is the

pending like or is pending like that that's basically that part. Now once you get to a place

that part. Now once you get to a place where you actually have to the problem is mutations don't have a dependency graph like they don't have anything to tie them. So, if you have multiple

tie them. So, if you have multiple things in flight, you need a way of like deciding that they're complete and you do want to hook the updates together.

I've talked about this before in past stream because you if you have multiple things in flight, you want them to entangle when they affect the same state, but you don't know. Optimistic

can help guide you to tell you like if they share optimistic state, then they probably they're entangled as well. But

it means we still need after the await a way of connecting the like data refresh or like the set state after mutation mechanism back to the thing. So this

problem does not go away. It's possible

that instead of having a transition, we have an action helper similar way. But

the difference with the action helpers is very very deliberate like when you're performing an action we we already have APIs like this in the router. So we

wrappers where you can like define them globally. I haven't completely landed on

globally. I haven't completely landed on it but the core part is with this sort of API design no one should be thinking I should go into my design system and

make select action design thing you know like that we were on that path right um but now since everything's a transition you don't need to go update it like the

router just works this way we don't need the router to go do wrap stuff in transitions your input components don't need to go like you you don't need to go through your whole ecosystem and be like

okay component authors cobalt guys come here go update all your stuff that use transitions like the the the end user will go like okay I have an action I

want to do with optimistic usually it's those two things you'll be like because you could technically if you don't have optimistic state you're probably not going to notice the entanglement problem

so most people who come in and do something naive will just in a click handler do the thing. And yes, it's if if they click it a bunch of times, it's possible the timing happens that like

the transition doesn't start until um it comes back from the action and they might miss each other or they might overlap and entangle, but they'll generally be okay. The second that you

go, okay, I need an action is when you go, I need optimistic state. At that

point, there's a real start and end. And

and in that case, you do need a way of removing the optimistic state, which means you do need a wrapper and you need to do it. But what I'm saying is people will get 80% of the way even further

before they ever realize that they need the action API. And and I think I think that's that's okay. You know what I mean?

That does that make sense? Like because

if you don't use an action, it will just view the stuff before the action and after the action as separate transitions, which is fine. If if if the

graph overlaps at some point, it will entangle them, but it's I I I think it's only the optimistic state that really gets us in trouble. So

that's that's when you know when you go when you get to that point where you're like I need to check the box ahead or when because I you know or I I mean even

checking the box ahead is not that bad because it's well no it is because you can tell you can tell the difference between an action and that because when

you do um something on the get side it's usually triggered from setting state right whereas an action is not triggered from setting state. An action is

triggered from like doing something async like up first like doing a post.

So like if you if you had something where you want to save a to-do whenever you checked it done, right?

There's two there's two things you do there, right? You check the to-do and

there, right? You check the to-do and then you if you want it to be optimistic and then you go save to the server, right? You can tell right away that

right? You can tell right away that that's an action because the the fact that there's a separate action, the actual saving it to the server. If all

you had to do is check the to-do and there's no saving to the server, then you don't need an action because you could just use the eager checkbox or something. But then, you know, if

something. But then, you know, if there's some downstream async that you wanted to do, right? And then the thing is I haven't actually showed the next example which is um the Ryan Florence

demo because solid doesn't have controlled inputs by default. Um

this demo lets the inputs get ahead. Like if you check a box, we don't reset it on you.

So you don't need to worry about um setting it to eager. You know, spelled the same way. So, if I go to Florida here, it's going to change to Florida before the UI gets consistent. See,

look, Florida, but now it's Miami, Florida. So, it didn't change the UI

Florida. So, it didn't change the UI until it could show Houston, Texas. And

while it's waiting, it's graying this out. But this shows California briefly

out. But this shows California briefly while this is graying out. So, generally

speaking, you want your inputs to tear.

It's because that's the best affordance for them. Having So, having inputs tear

for them. Having So, having inputs tear by default is kind of cool. And this

example is exactly the same as what we've been seeing, right? I'm going to close these ones down for a moment. Um,

like what I like now is it's like the spelt example. We don't have two-way binding,

example. We don't have two-way binding, but we have a select component now where I've generalized it and you know state states set state on

change. See, I'm just literally passing

change. See, I'm just literally passing the setter. Now, if this was data

the setter. Now, if this was data binding, I could go val I could do this in the same property, but who cares? And

then create async get the states then the state zero is the state and again yeah

just beautiful kind of logic graph here of just explaining how whenever the state changes fetch the cities for that state and then se and then whenever the

cities changes the selected city becomes the first city in the list right like it just chains down and you know if you want to add a third one you just add a third one you know that's why I did the country example But what's cool again is

in in here and then I showed the selection with a render. In fact, I show state in this.

render. In fact, I show state in this.

Let's put this example in the chat.

Yeah. Yeah. Yes. Yeah. Sorry. Uh this is true. I've been I've been I' Yeah. I've

true. I've been I've been I' Yeah. I've

been calling it latest pending eager. I

I I just Yeah.

Well, um the the the way it works essentially is create async turns async into a promise. Um and which means that get state here is a promise of string,

right? From a string, but states here,

right? From a string, but states here, oh right, Typescript isn't states here is just going to be um a string array.

It's just literally knows that it's a function of string array. Like I don't have the types in this playground.

Sorry, it's just this this called a TS file, but it's not actually. It's the JS output from the build. Um, but

essentially, it's non-nullable the way it works. So, what it happens is when it

it works. So, what it happens is when it hits a value like this that it can't read, it throws, but it only throws with inside this expression. And then this one goes, okay, well, I'm async and I can't resolve, so I throw. So, when I

read this, this throws again to this expression. This throws to this

expression. This throws to this expression. And then in the UI, we don't

expression. And then in the UI, we don't throw away the whole thing. We just

again throw within the scope of where we read it each place like here or here or you know um here we we we we only throw

we it doesn't cause us to rerender again. We only throw within the specific

again. We only throw within the specific effect or the specific reactive context.

Um, but what's cool about this is it means that the graph is kind of blocking um as data resolves, but the rendering

is not blocking. Um, and it makes it colorless because your component here has no clue that value or like this component has no clue really if value or options or any of these things are

async. But you know, you just have to

async. But you know, you just have to make a decision based on like like from an affordance standpoint, it's like, okay, well, if options are loading pending, then I'm going to show loading.

This is how I fake suspense here because um it would throw here and then we wouldn't get like there's a is pending has a like a default value that's used very rarely.

Um but so this means that initially when it throws it returns true. Um which is how when I refresh this page, it's actually loading. um not important

actually loading. um not important detail but my my my point is that like um what is my point? My point is that

essentially you consume the async at the edges of the system where it comes into the system and make them part of the reactivity graph so that your components don't need to worry about that detail.

They just basically are only asking a couple questions which is show me the value.

Is this the most up-to-date version of that value? That's that's basically the

that value? That's that's basically the gist of it.

So yeah, I mean what's some people saw this example and they're like is it weird that it waits though? The whole

point is the consistency. You don't want someone to see Miami, New York, right?

If I go here or sorry, let me Yeah. See,

if I'm here, Miami, Florida, you don't want it to be when I switch to New York to be Miami, New York here, which is what the D follow a lot of frameworks

would do um without a transition type mechanism. But this just works as I

mechanism. But this just works as I said, built into reactivity. And what's

so cool about this example is the select component literally just there's no suspense or anything. It's just like basically if this true wasn't here, it's not its responsibility. If I was

creating this for real, I would not have this true here. And when it originally loaded, select would be like I can't render and it would throw and suspense above it would trigger and show the

loading state. But after that point,

loading state. But after that point, it's capable of showing if it's ever out of date by the simple is pending wrapper here inside the select. And what's cool is because it's asking about its own

options. Doesn't care about anything

options. Doesn't care about anything else. You could also be like um

else. You could also be like um sorry. I mean, you could also listen to

sorry. I mean, you could also listen to other things, maybe value, I don't know.

But because it only cares about its own options, um it's generalized, right?

like this first select list has that same as pending check but because its options are never only pending at the beginning here never afterwards um

it doesn't trigger it only triggers this select to be loading which is one of the beautiful things about the modularity of this approach anyways if it throws how does it know when to retry does it await the signal that

through yes uh it's it's essentially not the the not ready error. Um

I mean the way I'm doing it right now is it throws it actually has a link to the node um or the promise if you want. So

we just what happens is the create async um primitive when it resolves

it um it actually sets the signal again which propagates the change down the map. So it's like initially it's like

map. So it's like initially it's like I'm not ready. So anyone who reads it throws and then when it finishes it sets a value, clears the error, propagates that through the graph.

creating results.

If it gets a different if sync gets a different promise than Yeah. I mean, I'm trying to

Yeah. I mean, I'm trying to Yes, actually there I actually had to fix this bug solid uh the the the the lazy version because the way it pulled

didn't matter. But in this version, I

didn't matter. But in this version, I actually had to look and see if if I got a new not ready error. I had to compare them and make sure um because when I didn't it actually didn't update properly um because it was already set

at that status and it wouldn't propagate properly. So I I know that's more of a

properly. So I I know that's more of a mechanical question but yeah would love to see Miami New York only because of deferred disposal

as a city depends on state so in theory it shouldn't happen. That would see me at Miami New York. No no no because the the the there's no deferred disposal on this because we're not releasing

anything. There's no condition here. The

anything. There's no condition here. The

the thing is the reality is when we switch to Florida here, we have Florida and unknown. So show

continuing to show Miami here briefly.

Um in that you know like in here is us holding the value in the past

but like or and like here Florida here like showing Texas even though we changed the Florida still showing the value in the past. My hope is and I don't know if we get this right away is

if this behavior is intuitive enough I'm never going to have to explain transition to anyone ever. Do you know what I mean? like it's it's just like this is async

is it pending or is it not? I I think that's the the kind of takeaway.

Yeah. Yeah. No, this is this is the gist of it. I'm just going to go into this

of it. I'm just going to go into this week in JavaScript, I think, now. Um if

there's not any more questions.

Um, a lot of cool stuff happened the last few weeks, but I I'm going to continue my work on this. Get the uh get the um JSX compilation working. It's

the same output of the JSX. I just need to I need to finish the rest of the implementation of this features in the signals library to actually have it uh you know be able to slot right into solid. Right now I've only I like I

solid. Right now I've only I like I haven't even done four component internals yet. So it's I literally just

internals yet. So it's I literally just have the async and sort of transitionesque model working. It's just

lovely because there's no transitions, you know. It it is a transition. It has

you know. It it is a transition. It has

the same behavior, but there's no transitions.

Yeah. Yeah. I mean, as a as a concept, I think so. I I think spelt is very much

think so. I I think spelt is very much on to something here. I just think that the the behavior just needs like a little bit of tweaking. It's hard. I

spent so much time recreating React's behavior in a more granular way or parallel way, but I I spent enough time to understand the reason for it.

And I think that uh I think React nailed that part. I think it's just we we just

that part. I think it's just we we just need to kind of blend both aspects together. I think it's really really

together. I think it's really really compelling and the fact that I said this just the reactive system is really cool.

Okay.

Very promising. Yeah. Yeah. I I mean, as I said, Tanner saw this and he was like, "Man, this is a freaking game changer."

He wanted to sell it before I was even finished providing it. He was already like telling people and I was like, "How do people do that?" Like, "How do they go on Twitter and be like, I got something really cool and it's like 500

likes.

I I I I literally post the thing, you know, showing it and it's like, oh yeah, 100 maybe. You know, no one gets the

100 maybe. You know, no one gets the mechanical stuff. I think when I make

mechanical stuff. I think when I make the actual demo, it'll be different, but like with the JSX and actually working and people can play with it fully working, it'll be different, but it's just like it's just [snorts] like there's a there's a technical

accomplishment here as well. Um, and

it's important to talk about this and the trade-offs and implications of this kind of designs up front so people understand like for example the set state thing pretty upsetting for some people but

what's the difference if you're going to like call flush anyways you know what I mean or this upupdate you know whatever you know thinking of all the recent Yeah, ads.

Yeah. Um, I find this API to cover all my use cases, give me flex to doing what I want with UI while I'm reading the default experience. See how Tanner

default experience. See how Tanner already saw this and I can't waitition of RC's.

Well, I mean their implementation RC's is actually RSC's um different architectures based on my article like the I covered that in my last stream. Tanner was actually

snuck in there before we did the microrend things and we actually talked about it a little bit. Um no one noticed which is the hilarious part about it.

Like all the stuff went on Twitter blew up but we actually I had Tanner on the previous week actually talking about it.

Um, and you know, cuz he got really excited again. I wrote up something. I'm

excited again. I wrote up something. I'm

like, "This is how you can do it." And

Tanner's like, "Yes, this is it. This is

it." And I was like, "Okay." Um,

his but he they're not making the generic serializer underneath the hood.

I was hoping they'd use servall. So,

realistically, it's not until Solid Kiss the feature that you're going to see these things together.

Transitions were the hardest thing when you started using solid. I think there's one gotcha here. It's the same issue that I see on solid router all the time.

You know that issue. Someone's going to go in and the router is going to work like this by default because wall solid works like this and they're going to put some async on the page and they're going to be like why when I navigate to the next page

does it hold on the current page and it doesn't show it till it's finished loading and and and you're going to be like look you can use is pending and or like is routing or

something. we'll have something

something. we'll have something equivalent from the router but that confusion is still going to exist or actually the other solutions you can nest a suspense boundary and that will isolate it that the the nested suspense I'm keeping the same transition behavior

so nested suspense boundaries will bail out like if you if you have like some global transitioning kind thing happening if you click to go to the next tab but you the next tab has a suspense

boundary we will opt out of the transition and just show that loading state and so which means it will navigate instantly there are ways to opt out in the same we opt out of

transitions today. So I think that like

transitions today. So I think that like um I think while you won't have to think about oh is this a transition? How do I do this? When do I transition? All that

do this? When do I transition? All that

like that whole category goes away.

There will be a new baseline here where it's like oh that's how async works.

Do do you know what I mean? Like it is a it is a shift. It's just like you're not going to be like when to transition is not going to be a question.

Yeah. Maybe post links and not play. No

links to playgrounds. Yeah.

Maybe you had to go through creating every chance to get this right. Yeah.

No, I mean it's it's it's true. I mean I I the to be fair earlier versions of solid were like that already but this version that I did was like the most

extensive version and it's a lot of work. Took me several months.

work. Took me several months.

Solid needs better marketers. I agree.

We'll get there. Harder always says like Solid hasn't been released yet, which is kind of a smack in the face, but I I get what he means.

It's it's kind of the other way around.

Transitions are global. So, it's more of like transitions actually, this is the hardest part about it, modeling it. They actually

it's like the tree falls in the woods kind of problem with same problem with suspense. It's yeah you have to you you

suspense. It's yeah you have to you you do propagate down the graph but it's the effects that actually the render effects that actually decide what the behavior

is. So whenever a new suspense boundary

is. So whenever a new suspense boundary is created it's it takes priority and it will and when you get to the effect and

it goes hey I'm not good. I may async, you know, or throw or whatever, whatever the situation is, it's going to communicate that up to the nearest new suspense boundary. If there's no new

suspense boundary. If there's no new suspense boundary, we we're not going back to fall back. We just pass it right through it, straight through. But if it hits a new suspense boundary, the new suspense boundary goes, "Okay, I got you.

I'm going to show your fall back and I'm not going to communicate it up. It's

going to stop with me." If you have multiple new suspense boundaries, then it's the nearest one. it'll stop and be like, "Okay, we're good." You know, now

if it gets past all the suspense boundaries, then that's when it hits the transition. And at that point, the

transition. And at that point, the transition is like, "Okay, I'm holding."

So, if you have a bunch of sources that are only read under new sense uh suspense boundary, there will be no transition. It will just switch to the

transition. It will just switch to the next thing and show the loading fallback. But if any source gets through

fallback. But if any source gets through or is above it or whatever, then it will register the transition until it finishes. And the suspense boundary may

finishes. And the suspense boundary may or may not be still visible at that point.

The real transitions with the APIs we lost along the way. Yeah. I mean, can we simplify this further? This is one of the questions I had in my head. Like, do

we even need create async? Now I like create async because it gives me very fundamental markers. But there's no

fundamental markers. But there's no argument really when you have a graph like this that literally every single signal like what if you didn't have create async and it was literally just

create memo cuz these are eager. The

reason we had create async partially was because they needed to be eager because we we didn't want to cause weird cascading problems where like you read lazily read the first async and then waited for it to read the second which

caused the fetch. We didn't want that.

These are eager. So technically

speaking, we could bake we could get rid of create async in this world and literally make every single signal async. If you return a promise, then

async. If you return a promise, then it's just participating in the graph.

Like it just does it. The problem with stores are tricky because you don't want anyone to be able to write to them anywhere. So

usually the way I handle that is have a proxy that says like while we're in the writer have special behavior. The

problem is async context. after they

wait, we lose that context and we don't know if we should be writing it anymore or whatn not and there's no way to restore it. Um, same problem is we use a

restore it. Um, same problem is we use a generator function because if you if you support async anywhere, create async also supports generators, async generators. So technically if every

generators. So technically if every signal could support async or async generators again it's not bad with a signal because you just return the value through. So then like the but so then

through. So then like the but so then like you just keep on yielding and you're fine. But with a store you're

you're fine. But with a store you're going to be doing fine grain updates.

you almost want to call this like the you almost have to call the setter every time like if the if if we had async context there's a world in which we

could unify all the all the APIs so that both async functions and async generators just worked in all uh

reactive expressions um right we wouldn't actually need create async um the one reason that made me like when I first looked at R3 three stay with create async was because for

SSR I wanted to make it pull based. One

of the interesting things is even though this is pushbased SSR was easier to model run once with pullbased so it's like okay well why why don't why don't I just do pullbased um essentially and

create async you kind of need it because you still need to make the promises eager so it's kind of like a pseudo push pull so I needed a marker to be like this is something we care about uh

actively rerunning um so I kept create a sync in um we'll we'll see how it goes as I get into hydration and uh finish with the SSR stuff but there is I I

think async context is a blocker but there is a world in which you do not need a specific create async primitive and literally it's just the behavior of the graph.

Thanks.

How do we support update? It's not going to be a built-in feature. You don't.

I mean, there is a way. You wrap it in a keyed show. If you again, this is not

keyed show. If you again, this is not your happy thing because if it's a keyed show, you know, everything below gets rendered. You make it a new suspense

rendered. You make it a new suspense boundary. That's how you do it. But I I

boundary. That's how you do it. But I I just don't Why? Like why?

Yeah, Keith. Yeah, exactly.

Yeah. I mean, the problem is who's expert enough to actually do this?

And secondly, without the depth, what are people going to get away take away from it? Just the

topics themselves are hard. Like if I had like a nice polished thing that I was like coming in to do, then like maybe we could pull that off. But like

today, like what I I I tried to edit down my stream sometimes and make videos. And it's like instead of five

videos. And it's like instead of five hours, which let's say three and a half hours on a topic, I I I cut like an hour out.

Like the biggest problem is when I'm into the stuff that's like the real like whoa moments. Um it's pretty difficult

whoa moments. Um it's pretty difficult like they I'm not as good at selling it, you know? I I know. I I watch a lot of

you know? I I know. I I watch a lot of live streaming. So, I know like like one

live streaming. So, I know like like one of the best ones is like speedruns like you I watch and they play the same thing over and over again and then it's almost like they cut the the the streamer's content like while they're talking to

the point that like it's more like the dialogue that they have through the talking and less the gameplay except for when they make big progress forward and because they're doing this repetitive

task. I like what do you cut? I I mean

task. I like what do you cut? I I mean it's possible, but I people have in the past come to me trying to suggest this like the content today does not make a bunch of short videos either. It's not

like Theo. Theo is on point. When he

comes in, he's like, "Okay, next topic."

Bang bang bang bang bang bang.

Sometimes it takes 45, sometimes there's an hour and a half and then he cuts it down to about an hour, an hour or 45 minutes and he's good to go. You don't

get to do that with this, I don't think.

Yes. So, it means with async context create sport streams. Yes, you're right.

still be willing to give a try.

I have made this longer obviously because I not have time to make it shorter. That's true. Yeah. The thing

shorter. That's true. Yeah. The thing

with shortening these deep are tips are l meaning I need a lot contest generalist from previous streams. Yeah.

Yeah. I mean, I could make a video of it, but like it's also not in I don't know if it's in video form yet. Like I I I would have to I feel like I would have to record things differently, like be like go time. Like I did that for a

while with this week in JavaScript. I

actually have short I actually separate off the videos for this week in JavaScript for a while and then I realized I was like whatever and I didn't bother publishing them. But I

actually broke them out because I'm on when I go there. I know the topics I'm going to go through and I'm going to give my take and I'm going to do that.

This is not the same sort of thing. Um,

that's why I watch back at 10x speed.

Yeah.

Anyway, today was long on a lot of stuff. Um, let's let's let's let's get

stuff. Um, let's let's let's let's get out of here. I think you guys are good on on the topics here. Let's let's do this. We can JavaScript as fast as we

this. We can JavaScript as fast as we humanly possibly can, which is still going to be long because so much stuff has happened. I'm just going to close

has happened. I'm just going to close down a bunch of these.

Keep on looking. It's like, what did I change?

It's fine. I changed them.

Like you want these examples still to work when you go give the conference talk next year.

All right. Just cleaning up bookkeeping.

Let me look at my notes to see if I missed anything that I wanted to talk about.

No.

Oh, do you know what I didn't do? We

didn't We didn't talk about Jose's talk.

Ah, it's fine. It's not that big of a deal. I wanted to I wanted to do that,

deal. I wanted to I wanted to do that, but maybe I can just find the excerpt that I'm looking for. Um,

let's do that briefly right now and then we'll get into this weekend.

Yeah, I mean it's possible to do something with like a timeout, but like I I it's it's odd to I guess it could be controlled because

technically like the arbitrary like it's new could be toggled so it is possible to opt And the problem is it just has such profound downstream impact that

like now you have to like it's always going to rip out. I don't know. It's

tricky.

Uh yeah. No. Um

let me see what I wanted to Yeah. Let me

see if I got my notes here.

Let's Let's look at this video for a little bit.

I'm gonna I because there's I have some relevance with it that I didn't have before and I so I want to look at this video but let's I have to change the way I'm

sharing my screen. Give me a second because in order to do that I need to share screen and we're going to watch it fast.

Um chat Chrome also shared audio. Sweet.

>> Just by thinking about it. Meet base 4.

>> Imagine being able to build an app with your name on it just by thinking about it. [music]

it. [music] Meet Bass 44, a complete AI creation platform.

>> Seriously, what what what was that? They

literally played the ad and then played it again.

>> Um, okay. Let's go. Playback speed like 1.5.

And then can I move my position? So I'm

like, yeah.

>> All right, let's let's let's go.

>> Joseph, I'm on the React team at Meta and I do not have a UI equals function of C in this talk. So, I got to do the next best thing.

>> Good idea. [snorts]

>> In this talk, I'm going to do a deep dive into the world of React performance.

On the React team, we take a holistic approach to performance, looking at the big picture of where time is spent in applications, and that's we featured in his talk, we added support for concurrency. Concurrency helps optimize

concurrency. Concurrency helps optimize our apps, whether they're IO bound, CPUbound, or both.

But in this talk, I'd like to zoom in a little bit more on rendering performance specifically. As part of React compiler,

specifically. As part of React compiler, we wanted to thoroughly understand exactly how well React is doing on rendering performance. You hear a lot of

rendering performance. You hear a lot of things online and as we all know, a lot of things you hear online are not necessarily true. Uh so we wanted to get

necessarily true. Uh so we wanted to get a really solid understanding for ourselves. So we kicked off what has

ourselves. So we kicked off what has turned into uh a multi-year exploration into Reacting performance. And that has meant diving into the world of incremental computation.

For those who aren't famili update build systems and UI react is an incremental UI system despite what some

>> No, that's Ricky's talk. This is um this is a this is a different talk.

This is this is this is the the React will never have signals talk but there are some important insights from this claim. Now our approach on this was to

claim. Now our approach on this was to create a series of benchmarks that are representative of different real world scenarios. One of the challenges with

scenarios. One of the challenges with benchmarks is obviously that you kind of end up focusing on one specific case and we don't want to you know overoptimize because that's not representative that that one case isn't representative of all apps. So we created a whole bunch of

all apps. So we created a whole bunch of different benchmarks. For this talk I'm

different benchmarks. For this talk I'm going to focus on just one uh but I'll share kind of some of the broader results at the end.

The draw benchmark that we that I want to focus on here is a highly highly highly simplified can't emphasize the word highly simplified enough uh prototyping app. Um I don't know why we

prototyping app. Um I don't know why we didn't call it prototyper. We called it draw. Just anyway we're not good at

draw. Just anyway we're not good at naming things. Um it supports creating

naming things. Um it supports creating text labels and that's about it. And the

UI is very simp very important thing we can take away from this.

Yeah.

So for this benchmark we have a script as like I said this is designed to be automated. We have a script that drives

automated. We have a script that drives all the interactions to create the React logo. My colleague Yan Passins actually

logo. My colleague Yan Passins actually took the SVG file and like was able to extract out the commands from that to actually write this. Yeah, it just keeps on going. So, we're gonna we're going to

on going. So, we're gonna we're going to skip ahead a little bit. You get the idea. It's a logo. Um, now might be hard

idea. It's a logo. Um, now might be hard to tell in there. That was actually to create the full logo at that 5,000 simulating clicks, simulating typing in the in the uh the width and height

fields, changing the X and Y position.

5,000 interactions to create that logo.

Now, the way the benchmark is set up is that each interaction synchronously updates the DOM, but we don't yield to the browser. So, there's no layout or

the browser. So, there's no layout or paint happening. So, when you actually

paint happening. So, when you actually run it, so I was kind of running an emoji just to let you see what's happening when you actually run it, you click run, and the browser appears to hang for a second, and then all you just see the finished logo, right? Because

we're just going to do layout and paint once.

>> This is an important distinction here.

Um I just want to throw out here because [clears throat] um there are benchmarks that uh just tests the synchronous time which is the

easiest thing to measure. Um GS

framework benchmark actually looks for the full paint which is actually kind of really interesting. uh UI bench from uh

really interesting. uh UI bench from uh the creator Eevee, you can actually toggle the mode whether it counts paint or not, which was really valuable early

on for me because on one hand the if you think about it, if you remove paint out of the equation, it's a lot more stable and it should be the overhead of the framework. But the weirdest thing when I

framework. But the weirdest thing when I was working with solid was for some reason we did better when we had the paint in compared to like it doesn't make any sense but how

could like a framework get worse like you think it just kind of scaled relatively or like you know but like solid surprisingly did better on benchmarks and which included paint

stuff and you think well you know that dirties everything up but it's like what are we doing that somehow I I mean And this wasn't a fluke. This is

consistently um I don't know are DOM updates more performant like is this something that could be changed in these other libraries? I'm not sure but it it was

libraries? I'm not sure but it it was just an interesting side effect. Is it

memory allocation actually having a bigger impact when like under like do is there a pressure under higher memory allocation? Do you know what I mean?

allocation? Do you know what I mean?

Like that causes things to scale worse when you add the pain to the layout. I'm

not sure. Not too important. I just it's it is interesting that most benchmarks actually include layout or paint in some way or they don't include them and then people cheat it by using like a request

animation frame or something like or like a like they set their timer on some way. This is like a classic way to cheat

way. This is like a classic way to cheat benchmarks. They're removing this aspect

benchmarks. They're removing this aspect out of the equation which is very respectable. It's just sometimes I do

respectable. It's just sometimes I do wonder if it removes the full story.

Just just just kind of throwing that out there.

>> In other words, this is measuring pure framework performance, right? That's

that's the whole point of this is we just want to see how much how fast can we make those those uh those updates.

Okay, so we're computer scientists. We

can set up an experiment.

>> Don't start your day with a gross piece of plastic.

>> Adding to the 4 billion plastic toothbrushes that get thrown.

>> And the one thing I remember about experiments is that I'm supposed to change one variable at a time. Um so

let's change one thing at a time. Well,

what are the variables to choose from?

In an incremental system, there are kind of two key architectural choices. The

data model and the update algorithm. So

for the draw benchmark, >> honestly, the channel has a choice whether they show ads on the video.

This is an interesting choice for your conference. Like don't get me wrong, I

conference. Like don't get me wrong, I put I do put ads on my long stream content, but like my conference talk recordings, I don't

like if I could because like yeah, I don't know. It's an interesting choice.

chose a a data model approach that a lot of folks in the community have asked about. We stored all the state all the

about. We stored all the state all the data for the app in a single state value and then pass that down via context. So

component >> reads the data for its entity from context and then accesses whatever properties it needs.

>> Right? Might have heard about context data context selectors or things like that. This is kind of the rough idea,

that. This is kind of the rough idea, right? We're just going to have this

right? We're just going to have this giant pack of data in context and we'll kind of pluck out at each component. The

one thing that I'm worried about about this >> is this doesn't say anything about like the different solutions like context is a container. You can use it as a

a container. You can use it as a dependency injection or you can use it to set state and rerender the whole tree but it doesn't actually say much set this context

and then just pass down the ID to each entity. Okay. So that it can in turn go

entity. Okay. So that it can in turn go and go actually read uh this data from the context.

>> Okay. And again, this is just a giant hashmap sort in state and then set as a >> and then they literally just >> that's our data model.

>> It's one state variable for the whole thing and then they trigger everything.

Been a while since I watched this. I

thought the takeaway was they can speed things up far greater optimizing data model exam, but they never tested signals with optimized data model. Yeah.

We never showed those results. Yeah, I

mean that that was the takeaway, but there's a couple things I think we should take from this just as fellow data fellow UI web UI scientists.

>> As we can see, this is basically a giant stress test for state and context as the representation.

>> Is it a giant stress test? See, to me, this feels like a giant stress test for um React's diffing capability because if

you put everything in a single giant U state, like did I did I get that right?

Use state new map entity set. If if if this doesn't seem like a test of the data, it seems like a test of React's ability to diff more than anything

because every time you change it thing, it needs to diff the whole freaking tree map stored in state and then set as a value in context. Okay, so that's our data model. As we can see, this is

data model. As we can see, this is basically a giant stress test for state and context as the representation for all your data in an app. How fast can we make it?

So this is the variable part of our experiment. So we chose to experiment

experiment. So we chose to experiment with different update algorithms given the same data model. React react

compiler and well we have the ones in a second. Let's look at the first let's

second. Let's look at the first let's just look at the results of these two first. So our hypothesis was that react

first. So our hypothesis was that react compiler would should hopefully fingers crossed we spent a lot of time on this thing be faster. Um but it could only be so much faster right because we're changing the context and every single component pulls from that context. So

how much faster can we really get when every component has to update at least somehow right? If this is your data

somehow right? If this is your data model a lot actually because React compiler by memoiza by memoizing

is going to be able to um like compared to the naive rer like this is like like this is like kind of terrible. It's like

rerender everything baseline. So if you can add memoization you're going to see significant like now if someone went through and handmemoized even that would be challenging here because the data

structure itself is one use state do you know what I mean like so your expectation here is actually this is one place where the react compiler should actually have a positive benefit >> okay so baseline first the results for

react now this version has minimal manual memorization >> remember this is 5,000 interactions taking just just shy of 4 seconds so this is the best case scenario And here's compiler.

>> Yeah.

>> Right. [applause]

>> Yeah. Not bad, right? We're pretty

happy. Like, okay, we could probably keep our jobs.

>> Yeah. I mean, this is really the best case scenario for the compiler because essentially non-memorized React. I I did I did in the JS framework benchmark um

the similar thing where I took like it wasn't even non-memorized like I had to like it because structurally it was smart. We did hoisting and stuff, but I

smart. We did hoisting and stuff, but I just removed all the memo calls and compared the compiler to not compiler.

And yeah, it went from two, it was actually slower, slightly slower, uh, naively than the transitions version that was hand optimized. And then the compiler brought it as you can see back

down to where you know almost where as we showed earlier in the stream almost down to where the hand compiled thing was which my conclusion was the compiler doesn't make code faster than hand

memorization or it's about the same but definitely makes your code faster. So I

think this is this is confirming that the compiler does memoization reasonably well. Right. Sorry, I didn't

reasonably well. Right. Sorry, I didn't pick it up the first time. Watch the

talk that they literally jam in one use state. That like that that almost makes

state. That like that that almost makes like all of this mute. Anyways, let's

keep on going.

>> So that's awesome. How though? What

exactly is happening? I just said every component has to update with it new context. So how did it actually get

context. So how did it actually get faster?

So in React when we render our UI creates a tree of what we call fiber nodes. The fibers correspond to

nodes. The fibers correspond to components. So you've probably seen

components. So you've probably seen diagrams like this in the past. And our

mental model is that oh the component is rerendering, right? So if draw updates then you have

right? So if draw updates then you have to propagate that value down and that means updating.

>> Yes. Yeah. Yeah. Yeah. Right. They use a mutable map rather than a plain object.

Must be copy the map on each update.

Yeah. Yeah. Exactly. Like it's it's basically immutable at that point because it needs to check everything anyway like

Yeah. I mean well okay [laughter] the

Yeah. I mean well okay [laughter] the benefit of the of a of of the mutable map there is one slight benefit is although not in this I think because

it's going to be primitive values it is possible to keep references I guess like do you deep clone or shallow clone you shall clone anyways yeah who am I kidding you you would shallow clone so

yeah yeah you're right this is odd I mean it saves you from shallow cloning I think you can set the same I I think you can set the same map each time and still trigger actually though I

don't know if the compiler would catch it. That's a good question. I don't

it. That's a good question. I don't

know. But yes, it seems the fact that it's a map might be like a small optimization or basically weird non.

Okay, so let's continue >> everything.

Well, with React compiler, that's not really what's happening.

>> No, >> for example, we only have to rerun the map if the entities change, right? if if

some other property of context changes, we don't have to rerun the map operation, right? The compiler is

operation, right? The compiler is actually splitting up this component into smaller pieces of logic. And

actually, we do the same thing on the item, too, right? Breaking it up. So,

for example, we only have to update the style property maybe if the width and the height of that entity have actually changed. And then, of course, we do this

changed. And then, of course, we do this for all the other components. The funny

thing is if anyone's seen my my talk um this talk uh there's I actually do this via slides where I'm showing like naively if you have a shopping cart and you have state up in the app and you

have button down here and the shopping cart here you know through the header user main and you do a mutation here and the state's kind of shared up high so it's in both places like in a context you end up rerending everything and then

the compiler lets you or your memorization lets you follow one path because even if you click here and trigger it up. You don't need the rerender down this way because there's like nothing changed on the buy button side. It's only on the cart side. Um, so

side. It's only on the cart side. Um, so

there's like a there's it's there is like a parallel here. Oh. Oh, sorry. You

guys can't see my my talk, right? Um,

sorry. I I forgot that I'm only sharing this one this one screen. Um, never

mind.

Contact value itself has to be recreated. And I think the map was a

recreated. And I think the map was a field in that value rather than the value itself. Fair enough. Yeah. Okay.

value itself. Fair enough. Yeah. Okay.

>> So, in the benchmark, if we've updated a single entity, sure, the context invalidates, the entities invalidate, we have to rerun our map, but then most of these entities are just going to be a no and things kind of basically kind of stop there.

>> What what I love though, this is showing like going down the one path, right?

Essentially, like that that's what I I was trying to highlight. Like you can memoize out the

highlight. Like you can memoize out the things that don't need to change, but you still go down the one path. And we

actually spend time updating here. So as

you can see as the number of entities grows, we're just mostly skipping the work on the on for all those entities and just focusing on where we need to.

So this is how react compiler is able to make this type of application faster.

>> So >> this is best case. Yeah.

>> React compiler can significantly improve the performance of context based apps.

>> Now this >> or it can significantly improve the performance of all your state in one

state variable ho hoisted high apps.

Right? Like context is no one bothers with prop drilling. So context is the most common way of doing it. But the the actual takeaway is that like if your state is hoisted high,

you React ends up having to do more work. Memorization allows you to follow

work. Memorization allows you to follow the branches.

>> Recurring question in this talk. Can we

go faster?

>> Yes.

>> Yes.

>> She's cheated. She's seen the you saw the dry run. Doesn't count. Um, now

there's been a lot of noise about signals in the community. What if we use signals? I heard they're fast.

signals? I heard they're fast.

>> The world's first titanium non-stick pan. Blow your hair back.

pan. Blow your hair back.

>> I'm Mike Miguel.

>> So, we built a prototype, a brand new approach to React. Groundup rewrite of the runtime using signals. Or well,

>> but I know the answer to this question because I already talked to them. They

did the same thing. They used one signal just like one used state.

Let's continue.

>> Not quite signals close. Pull based or lazy incremental computation graph. We

extended React compiler to emit the code for this translating existing React components and hooks to use this new runtime. It's pretty cool, right? I'll

runtime. It's pretty cool, right? I'll

talk about how this works in a moment.

Signals. We've heard so much about signals. I'm sure you are all really

signals. I'm sure you are all really really excited. You excited?

really excited. You excited?

>> He's playing it up so much, but it >> the results. Want to see the results?

Okay. Yeah. I'm just as excited to show them to you and not for the reason you're expecting.

>> Well, let's think here. If I had signals, one signal updates a state and I didn't have the React compiler, my expectation is the performance would be the same as

baseline React because I'm updating one state and then I have to go freaking diff everything basically.

Yeah. Oh yeah. No deep tracking. Yeah.

Yeah. Yeah. So my expectation is that it would be relatively the same performance as normal React. If it's faster than normal React without the compiler,

that's actually very impressive.

Our results so far.

That's impressive.

Yeah. So this is when we started to question our life choices. Maybe we're

just not cut out for this. And then we regained our senses. We double checked.

Okay. What if we just made a mistake because you know that happens. So we

took a signals based virtual DOMless library that scores well on popular benchmarks and we >> solidjs in case anyone was wondering draw to that library. The specific

library doesn't really matter as we'll see in a minute. Again this is an experiment. So we're changing one

experiment. So we're changing one variable at a time. So we're going to change the rendering you know the rendering algorithm.

>> You he is being honest here. It's just

it's it's difficult to tell because what's happening is um the ver he didn't want to change the shape of the solution. If you have one use state, you should you'd have one

signal right?

The library doesn't matter. I mean, in fact, if anything, um I the fact that their react forest was so much more performant than I would

have expected suggests that they did a lot of optimization um in the way that they propagated their change there, which is pretty impressive actually

because like it should be the same speed as normal React, not the compiler.

Right.

We ask ourselves if we made a mistake while ignoring the biggest mistake.

Well, I mean it's it's it's this from a very like procedural thing there. The problem

is you can't when things are different enough comparing apples to apples doesn't make sense.

But but like I think I think they did pretty good job here, right? Like from the perspective of like getting that much performance of by literally just

switching from use state to to use signal is actually kind of incredible.

Like I don't know what their signal implementation is, but I am very impressed because they didn't get any of the architectural gains, right? They didn't they didn't

gains, right? They didn't they didn't get to drill straight into the into the thing that changed. They literally are still rerendering the whole tree. Um,

I mean, okay. I I I I wonder if they if they were using something other than map, like if they were maybe using like a smart reactive map function and that kind of brought back some of the

memoization and that explains the difference. Like that's my guess. I

difference. Like that's my guess. I

wonder if they use something like our four component. So they had one signal

four component. So they had one signal and a four component and that would that would actually check for my head that might that might be that might get you in the right kind of zone.

>> So which means keeping the data model the same. Um, so we use the same

the same. Um, so we use the same approach, state passed down via context.

And I want to call out if you were to go and use a signals based library, this isn't how they'd recommend storing your data, right? And so it might you might

data, right? And so it might you might say that, oh, this is an unfair, you know, comparison. But the whole point is

know, comparison. But the whole point is we're doing an experiment to compare given this data model, >> right? Yeah. And so he he knows what

>> right? Yeah. And so he he knows what he's doing. He just doesn't like it it

he's doing. He just doesn't like it it doesn't quite highlight um like how absurd this is. Like do you know what this is like? Have you ever

seen uh DBimmon? Um it's the there which is like the Ryan Florence demo uh where they do the stuff on the screen and React like killed Ember in Angular. If

you ever look at the knockout implementation, we should do that for fun sometime on stream. It's literally

one signal and it makes no sense, but whoever implemented it couldn't care less. Like I guess, right? Like you

less. Like I guess, right? Like you

would never ever do this like ever like in 10 years like this. So it's it is an odd thing because the whole point is signals are to be fine grained and this

is not fine grained.

So it's like you almost go like is there any like the fact that they saw the other improvement is confusing actually like maybe that's why they thought they needed to do another comparison because

of the their signals like signal one signal should be identical to one use state in React that they're both atomic.

They're both immutable. They're the

exact same thing.

add a fancy compiler to React should be faster. Add um maybe a simple four

faster. Add um maybe a simple four component should be slightly faster, you know, than this the signal. But it it's essentially just one has more memorization and one has less

memorization when you have a single signal because this isn't about Yeah, I mean it's interesting. This

isn't about idiomatic usage in other libraries. The the problem is the

libraries. The the problem is the problem is it's difficult to talk about it because like it's like here we have a solution that works like

this and then be like for the sake of being consistent with what we already do, we're not actually going to use it the way anyone would consider using it.

So, it's like it's it's kind of like you're not really giving it a fair try, but let's continue.

He knows what he's doing. He doesn't

want you to take that part as a takeaway.

Yeah, I'm gathering that they they they they they used the memoization in the for loop like in just the loop essentially like like the math function.

That's the only place that really makes sense to to add it.

It it it does, which is why I we built stores. Um really people got to see my

stores. Um really people got to see my latest conference talk. We um We do it today in solid 2. If you use create async store um from the router, it it

handles it in a smart way.

Okay, let's keep on going.

>> What performance characteristics uh do we see given for this pre for this rendering model? So, how's it look?

rendering model? So, how's it look?

Okay, maybe maybe they're really fast, right? Signals are fast. All right, our

right? Signals are fast. All right, our results so far.

>> Yeah, they did a good good job with their minimal system.

So what's happening here? Well, in both our incremental prototype and in a typical signals, you end up with something that looks very vaguely like that.

>> I got tired of drawing boxes and aligning them. So I'm sorry that's the

aligning them. So I'm sorry that's the best you get today. On the left, we have our context, which really there's a state going into the context, but you get the idea. There's one giant input, and then we have a whole lot of derived computation. And then over here on the

computation. And then over here on the right, we have our places where we're going to use these values. These nodes

in the middle, we only want to compute them once, right? If a node has two inputs, we don't want to compute it twice. first with only half of the

twice. first with only half of the inputs updated and then again when all the inputs are updated. We want to make sure we compute each node at the right time only when it inputs have been updated.

So there's a very specific set of nodes in this case you need to pay close attention to this uh that are affected when this context changes. So watch

closely it's all of them. Um okay so so first we'll just mark them as changed.

We're not actually rec.

>> Okay. Okay. Okay. It's doing

notifications.

>> We'll go walk this tree and say give me the latest value.

>> And so we'll actually pull back along this tree. And so that if there's a

this tree. And so that if there's a fancy algorithm here, you actually want to go first and then if one of the nodes doesn't change, you kind of stop. And

it's fancy. You can look it up on blog post and stuff.

>> Okay. See, this suggests though that he has multiple nodes, not one signal, which is interesting. So we don't actually know this for It's funny. When

I talked to Joe, he made it sound like it was basically just like one thing, but this suggests that it's not one thing. Um I mean this is true but which

thing. Um I mean this is true but which is the reason this is relevant is because this is what R3 solves. Um the

because it it actually does it doesn't do the double coloring but let's continue.

>> Maybe Chief can explain it to you. Um

we're just going to skip over this, you know, high level here. Um but the point is we're actually visiting the graph again. So we're visiting the whole graph

again. So we're visiting the whole graph once to mark things as changed and then once to recmp compute. The biggest

problem is he he literally marks the whole graph, which makes me think it is like one signal. It's like he it's derived. It's basically one signal that

derived. It's basically one signal that deres, right? He he it can't fork. It's

deres, right? He he it can't fork. It's

not like projections essentially like or store. It's one signal and everything's

store. It's one signal and everything's derived from that signal. So you end up doing all the work again, right? Um

so when you start thinking about it, you're like that actually doesn't sound fast, does it?

Okay. So the signal style poll approach wasn't giving us the performance that we wanted.

But again, >> we do notify because there's the potential.

>> We actually got to the point that I just described a couple years ago before we even shared React compiler at the conference last year. The existing

incremental computation literature wasn't getting us faster. Um, but we have a lot of experience with incremental systems at Meta. In my 11 years at Meta, I've worked on Relay, which is an incremental in-memory database. Relay compiler, an incremental

database. Relay compiler, an incremental compiler for GraphQL, skip, which was an entire program for incremental computation. The compiler for skip was

computation. The compiler for skip was guess what? Written in skip as an

guess what? Written in skip as an incremental compiler. And now also

incremental compiler. And now also working on this. And in addition uh I've had the privilege to look closely at other incremental systems at meta like hack and flow.

And one thing that has stood out across all that experience is So, fast forward at least a year, numerous prototypes created and thrown away with, I got to say, amazing engineering work, incredibly clever

designs that just did not pan out until we hit upon uh a variant that we call React fur. It's a novel approach to

React fur. It's a novel approach to incremental rendering that uses a hybrid eager lazy algorithm. Now, it's

important to note this prototype is >> hybrid eager lazy algorithm.

As I said, it makes me think of uh like he's describing something like push pull, but I'm gathering it's not um it's not marking all the nodes the same way.

As I said, I would not be surprised if if it's the work on R3 is actually very similar to this where you have local

push push pull or like but mostly work off some kind of like height graph >> not support all the features of react but it does support a lot of common patterns more than enough to render the draw.

>> Honestly, I don't think signals are general purpose. Um they aren't super

general purpose. Um they aren't super general purpose because the consistency guarantees are uncommon but it is possible

you they are general purpose and like the they didn't like it's not like you're walking specifically like a BOM node or something like they they they you can apply them anywhere right like

that. So

that. So >> yeah, >> that said, before you get too excited, this is a constrained prototype. It is a long way away from shipping, >> right? This is which is something I

>> right? This is which is something I always have to remember when I when when you build the prototypes, they're always faster. Like I I used in this the

faster. Like I I used in this the benchmarks in Solid's repo, you'll see I actually have a version of Solid 1's algorithm without all the extra features. So I can test it to benchmark

features. So I can test it to benchmark against other things. And then inside Solid, I have the fully version because it's slower. there's constraints,

it's slower. there's constraints, there's limits, there's things that I couldn't do, but I still needed the pure version so I could actually benchmark those signals reactivity against other libraries because you know without the extra features so I could know that the

algorithm is fast. So a lot of times with these kind of like limited things the the real performance you get out the production version will be slower. Um

but we wanted to see you know if we do kind of strip things down to to the core how fast can we make it? That was that was the idea here. So this time you're probably excited for the right reason.

Yeah. Yeah, couple years of work to get there. We were pretty impressed. Pretty

there. We were pretty impressed. Pretty

happy.

>> If your workout still looks like this, you need to start training with AI. This

is AMP. It's

>> now a new React code name, a novel incremental algorithm. You probably have

incremental algorithm. You probably have a lot of questions. You have questions?

>> Yeah. Yeah. Okay. I guarantee the one you're >> This is the same thing as the data store guy. He has the fastest single

guy. He has the fastest single implication because it doesn't do dynamic tracking. I bet you that is

dynamic tracking. I bet you that is exactly what this is.

I would not be surprised because the problem is if you can't change the shape of the uh of the dynam of the dependencies then you can basically fix graphit and then you can basically

you a whole bunch of questions around like what happens at runtime can reduce which can you're so on the money dev I bet you that's what that is

okay still very impressive to see this kind of improvements.

But yes, I think you're right.

Yeah, sounds kind of like that's based on height stuff. I have computer eager and derives lazy. Yeah,

if they're in the mindset of come sides of depths, then why not bother run why then why bother runtime tracking? Well,

Marco had the same question and they actually ended up with runtime tracking.

Um but they didn't want to. Um the the the biggest thing is it's difficult to do things with like mutable reactivity in stores with runtime tracking. It's

it's harder.

You can shrink the graph down to user if you don't do traffic. I I my guess is that's what it is. I that is so freaking Yeah. Yes.

Yeah. Yes.

The overhead you're seeing at this point is just like React's own overhead of Yeah. I I think you're right. Let's keep

Yeah. I I think you're right. Let's keep

on going. We don't know. We're

speculating, but I think you're right. I

think that makes a lot of sense because we it's not like we haven't tested some of these things ourselves. So, let's

keep >> thinking of is not this. That's right.

We're just going to move right along. We

got we got to make things fast, people.

We got to keep going.

comp and a way to publish updates to a few records at a time.

>> And then we'll write a little hook that lets us, you know, read and subscribe to the store. Basically, I'm writing my own

the store. Basically, I'm writing my own using external store here is a bunch of to-dos, but you get the idea.

>> All right, so again, our results so far.

And now, oh wait, that's right, I forgot. So I'm not this is a comparison

forgot. So I'm not this is a comparison now. We've broken the experiment, right?

now. We've broken the experiment, right?

Right? Because the whole point of the experiment is you change one variable at a time. We're changing the wrong

a time. We're changing the wrong variable now. So this is not an

variable now. So this is not an experiment. This is just a comparison.

experiment. This is just a comparison.

But still, what are the results?

So is this just like it's funny that they decided to share this because if this is what I realized that this was my conclusion here, I wouldn't have concluded that I don't

need signals. I would have concluded

need signals. I would have concluded that I was doing the wrong experiment.

Like is isn't that the conclusion here?

If literally you could just pull an external store into React and beat every possible thing you've done, then you're probably looking at the wrong thing,

right? Like

right? Like cuz I mean I I'd love to see React with just external store versus without the compiler here. But the the gist of this

compiler here. But the the gist of this is if you aren't rerunning the tree because you're literally not using context or using a single signal to propagate everything derived. If you're

literally not running the tree and instead you just enter the React components in, you know, the 5,000 different locations or whatever, then that is going to be faster than any of

the propagation stuff. Basically, the

propagation doesn't matter here, whether you're using one U state, one U signal, or whatever. In in the scheme of things,

or whatever. In in the scheme of things, you go pick up Jotai or something and and some kind of external storage thing

and all of this doesn't matter, right?

Yeah. Pick up Redux. Why not?

Yeah. Yeah. Yeah. Perfect. Thanks, Mark.

Yeah. Even redux the cost of running ends callback selectors to figure out the components to rerender less than the cost of rerunning all the components.

Yes, I know the legend state guy. Yeah, cuz

now he's like, yeah, yeah, yeah, yeah.

Doesn't external storage still not work properly because of concurrent mode?

Yeah, I mean this is what Tanner asks at like literally every chance he can publicly on stage, but you know what I mean? The funny

thing is me and Joe are in a lot of agreement when I look at this talk so far. He basically said that there's a

far. He basically said that there's a more optimal way to do signals which I agree we've been working on it and that this propagation kind of like reactivity benchmarks doesn't really matter all

that much compared to just being able to pull the stuff out into a store. So

let's continue.

Oh yeah, and we didn't we did we barely, you know, we just we slightly rewrote things to use a store, but we're not like dramatically rewriting the code. um

and in particular because the the subscribe function, we can do very targeted updates in this store.

>> Okay, >> so why is this so fast? Well, if we go back to the incremental computation graph that we looked at for kind of the signal style graph. Um the issue was that the context was kind of upstream of everything. And so when that changed,

everything. And so when that changed, too much work downstream got invalidated. When we shift to a store,

invalidated. When we shift to a store, it's kind of like we can see inside that context. And so now when one entity

context. And so now when one entity changes, we're just invalidating way less work and way doing a lot less doing a lot less downstream.

But far enough along in the talk that you know what I'm going to say next. Can

we make it faster?

>> Yeah, there we go. All right. In

particular, what if we combine these ideas? Because I just said we changed

ideas? Because I just said we changed the rendering algorithm and we changed the data model. Like, can't you do both?

You can. So, React for similar external store. Here's where we are so far.

store. Here's where we are so far.

>> Yeah. [applause]

I did not believe that number when I saw it.

>> See, I do because here here's the thing.

He's created an optimal signals implementation and he's and he's doing looks like some kind of

finer grained like I don't even know what his external store fine grain update things but when I look at this

the the real crazy part is if you get a store like a a proxy store in like solid it is already granular.

Each property even nested is a separate signal essentially automatically. So

when you update the thing only the thing updates right and what's crazy about this is in order to get to this they needed to externalize the data

structure that when they say they use a different data structure they actually architect they they need to externalize it so that it wasn't in React's component render model and then they had

to make the render model um essentially be smarter so it doesn't diff as much use like a kind of almost like a push pull something similar to signals.

We will never see the results of this, but my suggest my guess is that solid with a store or spelt with a with their

state or whatever reactive system today if you just went walked over picked up those solutions is going to get numbers like the best one in this

chart today with zero effort. That's

just like where we are today. Um maybe

maybe slightly slower than this, maybe like a tiny bit because they've like super optimized this, you know, but generally this is like I don't see an argument

against signals here so much as like this is an argument for signals like is he he's basically like the biggest difference between between a fine grain renderer and react

is that whether you pass the signals through the component components like props or you put them in an external file like a store, none of the components rerender. Like it's literally

components rerender. Like it's literally the same thing. Like you can go like, okay, I mean maybe there's a couple extra getter calls, but like the the difference between saying putting it in

context or putting in external store, there's no difference, right? The the

problem wasn't that it was in context.

The problem was that there was one use state instead of like, you know, a thousand use states. So like

I don't know is that a weird takeaway to have from looking at this that basically separating the rendering from the state basically the like react antiattern is

actually the solution to their problem.

Basically not being react is the solution to their problem like I'm checking chat here if you do this talking about how signals

that work for eight years. Yeah,

maybe minus the dependency tracking for extra speed. Yeah, it's an argument for

extra speed. Yeah, it's an argument for using signals for state management, but I I like it's it's more than that. It's

an like you could that's why the legend stick guys are excited but it's more that's in the react ecosystem. It's an

argument not to use react because you get this benefit by not even using by just natively using a signals based framework like this is this whole thing

is just a nonissue. It's like you is it a external store is it your component state same thing like the whole concept category of problem just doesn't exist.

It's it's kind of crazy. I mean, it's it's I'm not saying React's bad model or anything. Generally speaking, like it's

anything. Generally speaking, like it's different and there's benefits of having this like rerender kind of thing. It it

makes things simple, but like this is not the conclusion that I was expecting, right? Like this is like like

expecting, right? Like this is like like if if stopped at React fur I you know, but then it's almost like everything from here invalidated everything that happened before. As you said, it went

happened before. As you said, it went from experiment to comparison. And this

makes you start going, well, does this like It mean it means that react okay it means that react is going to change its identity over the next few years if this

is the future if this future is to isolate data from rendering which has like never been the react approach it's sure it's not going to use quote signals

but it this is a direction that suggests that the compiler is probably going to be the one kind of masking over it a bit maybe but this is a suggestion that

reacts rethinking their fundamental render model internally at least you know like they'll give you the one appearance on the outside but internally it's actually working in a completely different way because

like isn't the whole benefit if the whole benefits comes from externalizing the stores and you don't want people to have to write everything as an external store well if they first of all if they're writing it all as an

external store then that's very different it's outside of the component and if you come up with a way to make people write it as if it were an external store. Then you're kind of like

external store. Then you're kind of like cheesing the physics.

Yeah, this is building.

It's kind of scary. I'm going to do it from the slides. I think it's also worth noting that the most odd context of this talk is about the traditional hoist up state pattern react.

Yeah, it's it's interesting.

And also the React team is a dead set that the only valid state management solution is React itself. They agree

external state is used, but they want to acknowledge it. Well, it's because they

acknowledge it. Well, it's because they want to control the async. They want the features to work. Like, don't get me wrong, I'm just as greedy.

It's just like like from like a solid perspective. We the difference is when

perspective. We the difference is when React came out, they were like here, use whatever state management you want, whatever models you want. We're just a render library.

Solid's like we're signals library.

We're state library fundamentally. So

like when you use solid, you you're using our state. You can use it in the component, you use it outside the component, you can use it wherever the hell you want, you know, but when you use solid, I mean there's like a trick where you can like sync it with an

external source. We do have a mechanism.

external source. We do have a mechanism.

So you can use like MobX instead of solid signals. But generally speaking

solid signals. But generally speaking like and it works actually pretty natively. But what I was trying to get

natively. But what I was trying to get at is like when you use anything in solid you're using our reactivity.

That's the gotcha. That's the

coloration. You need to be using signals. You know they might be hidden

signals. You know they might be hidden behind proxies or other stuff. Like if

if you if you make a state solution, a lot of the state solution people like stuff like Redux isn't bad because it's like literally a single immutable thing and then we just have it at the edges and then it becomes one of our stores

and then we do fine grain updates off it. Um but like people like Jotai, the

it. Um but like people like Jotai, the Jotai guys were like let's make Jotai for solid and then they're like yeah that's not going to happen. like it the atomic state management like that makes

no sense in solid because you' just be mapping one to one with signals like you get no benefit like zero benefit from that kind of thing you could like make a model that like look

like Jotai's APIs but you you'd be better just to wrap our signals in their API shape than actually use anything that they do right and I think I I think

like so in a sense right from the beginning we said we own the state and not just your global component state we own all your state and that's why we have no problem like walking into this

async world you know where and performance where this is kind of like you know I mean don't get me wrong there's a there's a conflict with that like when you if you're coming in and you're like I have my own state update

and I want to integrate with your system there's like a little bit more of a of like an issue like you know I did work a bit with Tener at one point in terms of like bridging that gap and you know you need specific solutions perhaps and I've

been working on making those easier with our diffing functionality and stuff, but but it means that more likely if you're someone like Tanner and you come in and you're looking at stuff, you just take

your APIs and wrap our stuff with it.

Essentially, it's all solid. Like solid

query uses create async or create resource today, but you you get what I'm saying? Like it's literally you're using

saying? Like it's literally you're using our state. It's like which is not the

our state. It's like which is not the case in React. And I think they're realizing that they have to have a solution here so that third parties can just like use their state and have it

being concurrent safe. See, it was really easy for us to be concurrent safe or whatever because literally every library in that uses solid essentially is using solid like they're already

using our state. So this is this is all ties together and makes sense. But it's

also kind of like if if the data now we're in a place where react is the render framework the compiler they have their own state solution like for external state store

like I mean it's fine it's just how much has the like what react is identity changed over time because because of this like I mean it's tricky

the fact that they've been able to persist and continue to evolve is is is obviously amazing thing but It's also kind of like you're like we've had enough time now to see that maybe there's like more directed

solutions that kind of accomplish like similar things but were already built this way to begin with.

Might as well just say for plus store emitting react altogether maybe.

The only way react command current running is if it owns the state that's why it uses has it limitation as an external state it's faster is a big deal. Yeah. Yeah. Yeah. Yeah. No, this

deal. Yeah. Yeah. Yeah. Yeah. No, this

is huge.

Now, now they want but my guess is they'll want to control that external state. So I don't see a change of render

state. So I don't see a change of render button in React components. Yes. Yes.

Yes. Yes. Exactly. I I'm just catching up. You probably said that while I was

up. You probably said that while I was spieling off five minutes ago.

Yeah. You

Mark knows what's up. Yeah, links don't work in YouTube chat. Yeah, that's

unfortunate.

Top few. There we go. There's the info you need.

They did Joe diol. They call it nano stars. Okay.

stars. Okay.

My I talked to Mark about this and my guess is they're going to create something kind of almost similar to one of our stores where if you if you the way I I talked about the stream today

the way that I handle concurrency of having managing both the pending and committed values on a per field or per

signal level in our stores essentially is how I imagine them doing this. And

then they can basically associate um these states with some in-flight transitions and basically have multiple realities kind of sitting on top of each other. And then you as long

as they provide the interface like the getter setter interface it should work.

I conceptually they I don't know how the subscription aspect would work in terms of updating for granularity but conceptually I I I

see something along those lines.

The difference is like when we approach it all, we were doing out a single s single signal at a time and then a storage is just a comp composition of that.

Yeah, they already have a Yeah, I'm not surprised has an international deal to full sync render but because they concurren now a prototype that does work current. Nice.

Okay.

And Van said the prototype is essentially an async signal if you squint at it. Yeah. Which is probably why Mark is here today. like

you know I I didn't get too much into the code implementation but essentially these are kind of like an individual reactive or I mean maybe not the

tracking bit but like like I don't know how the subscriptions happen but essentially from like the right side of having basically

kind of like multi- um committed versus pending value piece that can be you know exist at the same time. Anyways let's

let's finish this out.

really hope it's right. Um, okay. Now,

this is the point where we have to go back. Remember how I emphasized the

back. Remember how I emphasized the highly highly highly like triple highly super simplified at the beginning of the talk? This is a highly highly simplified

talk? This is a highly highly simplified benchmark.

>> Um, that makes it really great for optimizing the innermost workings of the rendering algorithm, but it also makes it less representative of real world scenarios. So, we also created other

scenarios. So, we also created other benchmarks that have a richer set of components and a more realistic data model. The draw was basically a key

model. The draw was basically a key value store as we saw. Um, now these other benchmarks are again not all the way to a real app, but they're much more representative and the results there were not quite as good. So this is a different benchmark again with React

compiler and a store and then react fur and a store and we can see that it is still a performance improvement but not quite the same magnitude as we were seeing on the draw app. Right. This is

just as we increase the complexity of our app, the rendering algorithm just becomes less critical to the performance and there's only there's just only so much we can actually make faster. Yeah.

>> And there's another aspect too.

>> Yes, it's faster but it's not the full react, right? And from a couple years of

react, right? And from a couple years of experiments, we know that adding back some features that people rely on every day with React would eat into these wins.

>> All right. But

>> yeah, I mean, basically they what they're saying is they may or may not ever do React for which I think is fair.

Like they're saying the compiler is close enough and that the store is the pole in my next.

>> No, no, no, no, no. It's time for a break. Um, okay. There's so much time.

break. Um, okay. There's so much time.

There's so much more that we wish we could time to get into. model is just as important, maybe more so than the particular incremental algorithm we choose.

>> Yes.

>> Second, our results suggest that domain specific approaches to incremental computation can be substantially faster than traditional incremental algorithms.

>> This I'm not as sure about because he he showed that, but then they're saying fur is domain specific,

but then he went on to say that fur probably doesn't make actually that big of a difference.

So in my head this makes sense but I I I'm not sure how much it applies in this case >> like signals which are pull based or or generally lazy

>> but also as we saw with that last slide improvements on one benchmark don't necessarily translate to other benchmarks and in some cases or even if they do they don't translate to the same magnitude right the draw benchmark is almost too simple and a richer set of

benchmarks trust us more cases worse during those couple years of experiments we had actually identified a few different ideas that looked really promising on benchmarks when we ported into real just

ultimately these numbers we really have to actually push them further to get into real app and see how they're going to things are going to play out.

All right, I can't take another ad.

We're just going to close this one down.

Um, all right. Uh, let's go back to sharing

all right. Uh, let's go back to sharing my screen.

Uh yeah, funny thing is he called key value store peak. Yeah, rally on key value

peak. Yeah, rally on key value observables. Yeah, the benchmark might

observables. Yeah, the benchmark might be simpler, but it let sounds enterprise wait for react. Yeah, I mean that's the g that's that's the game that always plays it. It's fine. If I had the most

plays it. It's fine. If I had the most popular solution, I would definitely keep on telling people like one day and betting on the future because honestly it's the hardest thing to do in the

world is to change or migrate or do something new, you know. So as long as you know React will do it one day, you know, or almost do it one day or whatever, it's enough for most people.

So yeah, I mean hold the wine, you know, do do what you got to do. I think that's I think that's fine. um

said the omnive adjapse he actually got.

So I I don't know if I if that's what he said. I think he just meant that the the

said. I think he just meant that the the difference wasn't as wasn't as understood.

Anyways, yeah. Uh I wanted to do that. Uh let

yeah. Uh I wanted to do that. Uh let

let's see if I got a couple more things to to look at here um before we head out. But let's see. What do we got?

out. But let's see. What do we got?

Let's do a quick this week in JavaScript um home profile. Give me a second. I'm just

profile. Give me a second. I'm just

going to actually switch in my head here while I get a couple tabs open.

It's been it's been a it's been a sweet minute since we did a stream. I as I said I went and did a conference talk, did a few other things. I think the last

stream we did was on October 24th.

So that's our threshold.

All right, let me scroll back to October 24th.

All right, looks like solid stuff is good to begin with. And then one more duplicate.

One more section.

Bookmarks.

Oh, wow. That's funny. We talked about the directives thing on stream, but then it like blew up like after the stream.

So that's actually where we start from.

But I'm going to start with Salt. Let's

do this and talk about this week in JavaScript.

Okay.

All right. So, let's go. Let's go.

Um, yeah, I'm going to start with some solid stuff because it's probably the easiest stuff. It just it's first big

easiest stuff. It just it's first big solid news. We hit 1 million downloads a

solid news. We hit 1 million downloads a week, which is huge for us. Um,

hopefully we're still doing that right now. Let's see. MPM SolidJS.

now. Let's see. MPM SolidJS.

Be really sad if we hit that threshold and then uh it just drop right off.

Okay. No, we're still climbing on this really beautiful trajectory here from the last six months. So, we're almost at 1.1 now.

I I we were at 300,000 a year ago. Um it's it's been incredible growth, especially on a year where we haven't released anything like major.

Just been doing fixes on solid doing you know small bug fixes on solid start.

I've been very deep into my research.

I'm hoping, you know, people are just realizing the the power of using solid.

The the the common pattern I'm seeing is solid's getting used a lot in React tooling where people want lightweight stuff to use around React. Um the

tanstack dev tools, tanstack router dev tools um are big examples of this. Uh I

think Aiden from Million just made another tool using using Solid. Um but

yeah so is my screen sharing working okay?

Yeah. Okay. Just double checking.

I it depend. Well react grab here. The real question is,

here. The real question is, oh, nice. I mean, React Grabs only only

oh, nice. I mean, React Grabs only only 7,000 uh downloads a week, but that's because

we're a direct dependency. That's 7,000

new downloads for solid a week.

So, props. Yeah.

gets the use of the web components in React apps that too.

But yeah, I mean for whatever reason I I think more people use Solid than they realize. And I think this is it's funny.

realize. And I think this is it's funny.

We're in this weird place where I feel like we're way less known than spelt for example even the next closest one cuz like I mean what's npm trends? How are

we doing these days? MPM trends salt js I'm pretty sure the next biggest library is spelt after us.

Yeah. Yeah. Selt's around 2 million. So

we're like half as stealth downloads.

But I feel like we're also like less than half of spelts get up stars. So

like way more people know about spelt than they know about solid. You know you see that on popularity polls and stuff like where it's like how many people have heard of us. Not many people have

heard of us. So um this is a good saturation for us like versus I think the number of people who know about solid versus the number of people who use it. That being said, we're just

use it. That being said, we're just peeons all all of us together compared to React, right? Like I I like that there's a white space below the line now.

But you know what's interesting people don't realize this pact is actually the second most downloaded framework according to this.

I think like if I know everyone knows about Angular and Vue, but was it Angular at Angular Core?

Angular core.

Yeah, look look look at the scope of things. Angular is like here. Let's do

things. Angular is like here. Let's do

what's view.

Yeah, pact past view recently.

So, let's remove react because it's just freaking depressing. and and look at the

freaking depressing. and and look at the stuff again. Like

stuff again. Like I I I mean I don't I don't even know how to explain React's growth over time recently. Maybe AI. It's just we're

recently. Maybe AI. It's just we're getting to such a weird place where like like Pact saw a spike because of the remix announcement around here, but otherwise you can see it is still on a

rather good trajectory, so to speak. Um

it's just interesting. Downloads aren't

everything obviously. It's just it's it's like this spread has pre-act at 8 million or 9 million and solid at the bottom here at uh about 1 million. So

they're about 10 times more downloaded.

But like then you go to React. This

wasn't always this way. If we go back past a year and React is like 50 so 50 times, right? See if you go back five years.

Uh let's go back farther. All time

application error. H we killed it. No.

Yeah, it literally can't handle it.

It's because of React's data. Okay,

whatever. If we if we go back in time, what you will see is that Vue and Angular used to be about about like 5 years ago about half of React's downloads. But now React has gone 10

downloads. But now React has gone 10 times big higher on downloads. As I

said, downloads aren't everything, but it's it's like all of us are like like this compared to

React. So, it's it's kind of funny.

React. So, it's it's kind of funny.

Yeah.

Salt is huge at this point.

Um, spell cro.

What happened to December 24th? A

Christmas miracle. I'm not really worried about that. But most time during Christmas break, framework downloads dip. Apparently last year we had a

dip. Apparently last year we had a spike. I guess people were interested.

spike. I guess people were interested.

Yeah. Then compare React to WordPress and it's like not even close. Yeah, I I know. It's all matter. Add lit. You want

know. It's all matter. Add lit. You want

me to add lit? Sure. Let's add lit.

Lit's actually surprisingly more used than people realize.

lit actually slides in there nicely between Angular and Felt. So, you know, props to them there. This here, by the

way, was the weird spike. Like, there's

a I don't there was a weird spike a couple years ago that happened on a bunch of frameworks. Oh, no. They they

they did they take them out? The weird

spike? Oh, no. They're back here. Okay.

No, this was must have been the spelt 5 release then. that spike there was like

release then. that spike there was like a Okay, that makes sense. Was this

around December? No, August. What?

That's an interesting spike. August

2025.

Yeah, I don't know what that spike is.

Anyways, doesn't really matter.

Um, but yeah, lit lit is nice in here around 4 mil about double spelt. A

little bit under angular core. Yeah,

it's not even the big three anymore.

Yeah, I mean it's it's like React and literally everyone else.

Yeah. Yeah.

This is the world that remix. I mean,

it's harder every day. Like I love my buddies over here. Uh, that's not it.

Over.

But like getting ground is so hard.

It's so hard.

Uh, let's remove React. It's taking up too much of space. Let's remove View.

Let's remove what's the next one? Angular.

Let's remove lit.

Remove fault. It's just it's Yeah. So freaking hard.

Yeah. So freaking hard.

Is this the right package? No. I mean,

it's still going up slightly. It's

10,000 12,000. It just

is Remix 3 something we can download yet?

Probably not.

Yeah. No, it it's it's just I mean we have to get over the training bias at some point. I'm not worried about that

some point. I'm not worried about that as much, but like it's just so propagated.

Stencil. Is stencil still stencil still a thing?

I didn't even realize stencil was still around. Stencil core.

around. Stencil core.

Okay. Stencil is still stencil. I didn't

realize stencil was that used. Props.

They took off quicker because they were react like for the virtual DOM. But it

looks like we've finally uh we finally caught up to them. Nice. The one that I I often look at is my buddies over here, Astro.

We're very close. We've always been very close to Astro. Yeah, our curve is almost identical.

It's like we just sit right on top of each other. They're great to use

each other. They're great to use together and they're Yeah, this is part of my whole theory about the time that you come out having a huge impact like the way the curves line up.

Astro and US have like almost the solid was a slow start but because no one really paid attention to us before 1.0 know, but yeah. Anyway,

I mean, we already showed lit, so Stencil's way lower because or it's Stencil's about 1 million, a little under solid, maybe like 800,000, and Lit's like 4 million.

Um, yeah, [laughter] this makes sense. I

use them together. Yeah, I mean, this must be why this graph is this is this is Jark's usage graph right here.

But no, yeah, I it's it's a good combination. Um, okay. Um,

combination. Um, okay. Um,

hackathon solid tanstack start hackathon means you can use solid. I didn't

realize this at first, but and I was like, Tanner, why don't you give me a heads up? Well, apparently the ComX guys

heads up? Well, apparently the ComX guys like just basically just went ahead with themselves and everyone jumped on. Uh,

Code Rabbit, Sentry, Cloudflare. Look,

640,000 in prizes.

Just everyone wants to be part of this.

But what's cool and I big props is full stack framework powered by Tanac router for react and solid secondass citizen makes me very excited you know show that

solid love out there. Um awesome awesome awesome awesome um very cool.

Yeah.

Just throwing that out there.

I was like stoked when we got like 15,000 or 20,000 or whatever for our last hackathon 64 I I guys.

Yeah. Did you know that tic start with Soljs I built a live hockey draft kit?

Very very cool. Did I not like this one already?

Native script. I I like highlighting when people use Solid for like stuff that's like people don't realize you can do native development with it, you know, stuff like that. Um,

conference talk.

Yeah, here we go. React grab written with solid. Turns out having to reactive

with solid. Turns out having to reactive page can cause errors, blah blah blah. A

lot of signals here, but at least there's more than one. Um,

very cool though.

Love Aiden's work. So

panstack dev tools feature as long as having v plugin even for friends of solid. Yeah, this is side note people

solid. Yeah, this is side note people the dev tools for tanstack start have the this cool like live component view that it works even for solid as well. So

very cool seeing this stuff like evolved in the space, having a framework that cares that much about DX working so like seamlessly with us for mission valot

it's so cool to be put on that list. um

you know like you know we're we're when new libraries come out they're they're thinking of us now which is a big big change before you know I there might not be the big three

but you know there's the there's React and then the the small seven you know so yeah

I don't know it's it's it's funny um but awesome okay let's keep Um, what what else do we got here? Uh, bookmarks.

Oh, yeah. It's funny. I I didn't talk about this before, but this is this is actually general software product advice. Never name a feature X mode. The

advice. Never name a feature X mode. The

word mode denotes there are multiple.

You were telling yourself that there are multiple ways that you use your product.

We must all learn. At least lie and pretend that's not the case. Don't use

that word ever. I don't know. He wasn't

probably talking about concurrent mode but it made me think of concurrent mode and it made me think about the async features. This is what earlier on the

features. This is what earlier on the when I was talking about the mode thing I was just like he is so right like the fact that the same thing like we do have

modes definitely you know like we have uh like SSR or hydration versus not you know like there are things that operate under different pretenses

um but yeah definitely um sorry Dev this is great the idea we will regret reinventing RPC yeah it's so funny a lot of the chatter

um about React's source felt remote functions and you know how amazing they are and don't get me wrong they are definitely amazing. It's just when we

definitely amazing. It's just when we basically unveiled the same thing there's there's details but Rich was not a big fan originally. He actually had a whole conference talk where he kind of

picked apart why he didn't like it. I I

understand that he addressed a lot of those with the design of felt but m you know that was never the case the thing that I was worried about. It's all about the mechanics of how the thing needs to

work. And I'm glad that he kind of we

work. And I'm glad that he kind of we got to the same place. Um, but it is sometimes interesting.

You know, we might still regret reinventing RPCs. I'm not saying there

reinventing RPCs. I'm not saying there there isn't a possibility there, but I just bookmarked this because it reminded me of that talk that was like very brutal about server functions and whatnot.

Maybe a little poor former to literally every library for your act. Yeah,

that's that's that's probably how it goes. It's nice.

goes. It's nice.

Oh, yeah. And then

Yeah, I don't even want to talk about directives.

Maybe. Did we talk about them last time?

Let's pretend we talked about them last time.

Yeah, we're going to pretend we talked about them last time. Um, just look at my other bookmarks here.

this about remix.

Oh yeah, this was an interesting interaction. You probably heard Remix 3

interaction. You probably heard Remix 3 doesn't use React. It use GX but not React. This means that you cannot use

React. This means that you cannot use any React library with it's 99.9% of them use hooks which won't run in R3. I

thought it was a huge advantage until I realized one thing, one simple trick.

It's simpler to integrate vanilla libraries R3 Remix 3 than it has ever been with React. It's funny R3 and Remix 3 is going to confuse me. We're talking

super early. Part of remix is going to improve easier. Why? Because remix feels

improve easier. Why? Because remix feels and is just JavaScript. It turns out pairing JS with JS is rather nice given how focused is on events. All you need to do is define specific events your library integrating scribe. Let's say

the team takes your new remix.

And right responses to be fair this is true of any run component body once framework especially nonb ones like sol and spell. I think view even um is

and spell. I think view even um is relatively easy to integrate because of the body component body runs thing. More

often vanilla libraries are dealing with direct DOM refs and wiring subscribers will generally fit into reactivity of the given solution. So while it's been my experience that this is true, it's nothing new outside of React and people have still generally will make rappers

albeit simpler ones simply get the component interface, right? You you want to like absorb it as a component rather than just like write a bunch of ref wiring code yourself. The real obstacle is the fact that alone doesn't stop people from targeting React

specifically. So even if all generic

specifically. So even if all generic solutions work out of the box, someone will always be able to point out some library that just came out 3 months ago that everyone has to use and only React, then you will get your own port a couple

months after, but by then everyone has moved on. Repeat. I mean, that's a very

moved on. Repeat. I mean, that's a very pessimistic view, but it has been my experience. I just thought it was

experience. I just thought it was interesting, you know, like it's the remix kind of like a community discovering something that's been like true of Sweld and Solid for years. Like

literally, you just, you know, vanilla just kind of pops right in your lap. Um

um suppose f exists but you know he's talking about like generic like tan stack it's good. Yeah, signals aren't why people like Solid more than React.

It's the component closure. I suppose

it's more obvious in Remix 3 to say this is integration part for everything though. In my ignorance, I imagine you'd

though. In my ignorance, I imagine you'd have to turn everything to a signal to get solved update when integrating. I I

love Dev's response. This is so cheeky.

You're not wrong. Solid does require turn things to signal so that update changed.

Change it to signal do something set state. let state versus single state. I

state. let state versus single state. I

I he this is such a funny thing. He's

showing that it's the calling the set state versus calling the set state and then calling update it. Like obviously

you it's one less line of code. Um this

is an oversimplification. I just think it's sorry it's funny. Um

yeah, but yeah, turning something into a signal isn't a big deal and it's not the end of the story. You should actually be

the story. You should actually be driving data. Um, but just be humorous a

driving data. Um, but just be humorous a little bit. Um, let me look here.

little bit. Um, let me look here.

Um, yeah.

Why did I bookmark my own post? I'll get

back to that.

That's funny.

Do I want to talk about this right now?

Let's leave that to later. Let's keep on going.

Yeah, we're going to skip directives.

Did I not talk about this on stream? I

guess not. Uh the post about building uh stuff in 10 different frameworks.

I guess I never talked about this. This

article is a little long and hard to read because there's a lot of repetition. The takeaways I think are

repetition. The takeaways I think are mentioned multiple. But I think this is

mentioned multiple. But I think this is basically this.

Did we not talk about this?

I don't know. Basically,

I was tapped on the shoulder to see if they were doing the right things and then I was worried about like store performance and I had no idea that they were going to do loading performance. Um

what's interesting here is that um compressed wise um I don't know why felt doesn't compress as well as we do and for some reason they're ordering it's

non-compressed. type I generally always

non-compressed. type I generally always or it's prep.

Yeah. Fell kit 54 solid 41 spell kit 47 solid 21. So we're actually if you

solid 21. So we're actually if you actually use compressed size instead of non-compressed size we're actually like probably the third.

It's basically Marco Astro Solid start in terms of code size which is interesting when you have a framework like quick but quick quick doesn't hydrate but its code size is a little bit larger but it scales better over

time so it's it makes sense why a simple demo um but I I it was interesting start performed really well in this comparison

both in code size and loading speed I think it was it was the the only takeaway I I don't know if they I thought there was more graphs. I thought

there was I thought there like there's one that maybe this that's a bundle size. I thought there was one about loading size.

Does it this article the article get gutted? Yeah, I think maybe the article

gutted? Yeah, I think maybe the article got gutted because there's one that originally had like first contentful paint and stuff.

Yeah, that's weird. I don't know what happened to it. Anyways, doesn't really matter. Um, solid solid start did very

matter. Um, solid solid start did very well. Handstack start with solid did

well. Handstack start with solid did decently well, which is interesting because you could compare it with React and see the difference. Um, not just in size, but on loading time, but it looks like all the loading times are gone. So,

in either case, I think the the only loser here was Nex.js, JS which yeah I mean

I don't know it's not too surprising not much to say on this one. Um

I it just yeah I don't know. This has been one of those things where it's like you're looking for the right kind of comparison and you just I'm just not finding it's it's challenging now to really

differentiate a lot of the solutions.

Even if there's like a performance difference, you're kind of like, yeah, I don't know.

Joe did this. Yeah,

this is the only Okay. Yeah. A thing you can do when seeing a techno choice you disagree with, pause, take a breath, be curious, ask yourself why they might have done that, and ask the officers why they did that. In what context did they

do they don't? Yeah. This has been really helpful for me. I spent you this whole stream was me analyzing why reactants felt did what they did. Um,

and this has been very helpful for me. I

do this a lot and I really have to thank my time with Marco for influencing that because Marco originally made me really challenge my assumptions. I have to like put on a different hat when designing

for Marco and designing for Solid. So,

um, yeah, I think it's important that we always kind of step back and think about like the reason why different decisions than what you think you'd make would happen. We talked about React APIs

happen. We talked about React APIs today, like why do they look the way they do? They they start making a lot

they do? They they start making a lot more sense when you think of async, you know, stuff like that.

It should be archived on your YouTube.

Yeah.

He said there's a bug in the benchmark.

Okay. Well, whatever.

We already talked about the hackathon.

Do we want to talk about isomeorphic first? We can talk about briefly. We

first? We can talk about briefly. We

talked about this last stream, so I'm not I don't need to go over to the article very much, but there's a a different approach to server components that I think is kind of interesting that

I kind of designed out and Tanner's going ahead and implementing. Um I to help people understand why it's important. I think this is an approach

important. I think this is an approach to server components that actually doesn't make things far on the right here like apps actually feel the pain.

It's the way I think I would approach it if I you know was trying to add it. I do

see a huge benefit to this approach like the typical RSC approach. It just I understand why there's friction on this side of the graph and I I really was trying my hardest to figure out if I

could extend this the whole way and I just didn't ever succeed. And I think this mechanism that I kind of came up with, well, it doesn't it's not as nice over here. I think I think it's

over here. I think I think it's interesting and it'll be interesting to see how it works in Tanstack, but as someone kind of thinking spa first, spa

SSR, it's the next kind of natural step here. So, um,

here. So, um, we talked about last stream, so I don't need to get into it again. If you guys if you're interested, check out my segment with Tanner right before um the

the the um microrend stuff. I think the more interesting thing here is that is that we're kind of building this idea of like a almost client first but

isomeorphic first framework. I've talked

about this on my previous like uh like where frameworks are heading streams every year where I was talking about this big divide between like stuff that's working like server components or islands and things that are spa first

like you know typical SSR like spell kit tanexard or even quick like there is a split architecturally on the mentality and I feel like um funnily enough react server

components and islands are on one side and like ourselves tanstack felt kid um and quick are kind of like on the other side and ducks also on this side. Um so

it's interesting to see how both sides kind of develop because I think they're both viable approaches but this was like kind of making a manifesto almost. Um

which we talked about last stream dev tools. Cool.

dev tools. Cool.

This one cracks me up. Let's talk about this for a minute.

The HTMX guy was like there will never be another version. basically he's like there will no be but never they're apparently releasing a new version of HTMX and I'm like I thought it was so

like I I got why they he thought that he wouldn't need to and he was trying to build stuff into the browser but I I said this at the time you can probably go f back and find when it when they when he released the

whole thing where was like there won't be another version of HTMX blah blah blah I'm like I said that was the cockiest position one could basically take ever that's like that's like saying that I did it the first time and I 100%

got it right. Like that is like you you have to have some balls to to come out and and say that and and you know maybe he does. Um

he does. Um but like uh we're all just human after all. You

know like I I I think I think change is a constant. So this is this shouldn't

a constant. So this is this shouldn't have been a surprise to anyone. Um, you

know, part of me was like we shouldn't revel in stagnation, but this is real realistic here. He's not saying he's not

realistic here. He's not saying he's not saying stagnation like he what something came about that was worth changing and worth updating and they're going to do it. So, it's not about stagnation, but

it. So, it's not about stagnation, but it's it's about, you know, humility, I think. Um, that's only my perspective

think. Um, that's only my perspective obviously, you know.

Yeah.

Yeah. I mean, that's perfectly fine, right? I'm not saying it doesn't matter

right? I'm not saying it doesn't matter what it is. It's it's the fact that it could be the most trivial thing. It's

just there will be more changes. Yeah, there

will.

Yeah. Uh, if you didn't watch previous stream, there's a whole road map for Solid Start V2 built on Solid 2.0.

They're already in progress. We're kind

of building these things out in parallel. Um, there's an update to Solid

parallel. Um, there's an update to Solid Start pre.0 that's getting set up

Start pre.0 that's getting set up getting off and then the final bit will be with 2.0. So like there's already a plan in place in a road map. If you go to the solid start repo, you will find

it. And actually's

it. And actually's talk at beat comp this year was the plan for this. actually he did a whole

for this. actually he did a whole conference talk on it.

Of course, it doesn't matter the it's not it doesn't matter what the change is. It's the fact if you just were like

is. It's the fact if you just were like I'm never doing another version that is so like like I I don't I don't care who you are, you know? It it doesn't matter

like or never like another major version. That's that's like it it

version. That's that's like it it doesn't matter what the change is.

That's just like the peak of of so a bunch of breaking changes. Yeah. I

mean things get better like things change. It's just it's it's tricky when you're positioning is like web's too complicated. Things should

never change. And then you're like, then you're like, but I do need to change myself, you know, it's like, yeah, I I love this meme. Sorry, just moving

on. The use effect problem.

on. The use effect problem.

It's just because people are wired this way. I think everyone's seen this meme

way. I think everyone's seen this meme by this point.

you know, the fact that like everything fits in the square hole.

Whose whose fault is that? You can say it's a design flaw in this unit. And I I could agree with that, but sometimes

like the square is the right is the like the right shape hole and we need to realize that there's more specific solutions that fall fit better.

Uh anyway, um it was just there's so many people. It's

funny on again on Blue Sky people like, "Haha, that's a funny meme." On here it was just like tons of people just being like, "React is the worst. React is the

worst. React is the worst. React is the

worst. React is the worst. React is the worst."

worst." Or people being like, "It works. Why

should anyone be bothered?" That's

scary, too. Um

uh uh but yeah, I mean it's fine. Let's

keep on going. Um we talked about use effect.

I want to show this this quick little clip here.

We talked about RxJS a bit at the beginning.

This I look at this answer originally.

It was from July 22nd, 2011. This was so fundamental to my understanding of why KnockoutJS was great. And

um I just I'm going to love this. I

found it again. I figured I was looking around and this was like what makes Knockout or Signal special. They called

them observables because which is confusing because RX also had observables and then there's this whole that's why they got thing. But he this explanation perfectly explains to me why

like signals exist and why stuff like solid exists versus just using RxJS. Um

I'm very familiar with Rx JavaScript having recently used it heavily a big project and aspects of the design and knockout are made with my RX experience in mind. The key difference between

in mind. The key difference between knockout implementation of observer pattern RX is that knockout automatically infers the association and dependencies between observables from regular procedural code without you having to specify them up front through special functional API. I want Knockout

to use regular procedural imperative style code as it's more familiar and approachable for most developers.

Another difference is RX is optimized for composing streams of events without state. At first, I was enthusiastic

state. At first, I was enthusiastic about this and its functional purity, but after time it felt increasingly like I was jumping through awkward hoops and had to invent extra ways to simulate state to manage UI commands sufficiently. That's why in knockout all

sufficiently. That's why in knockout all of variables can be treated as stateful.

For example, you can always read their latest value, which is cache by the way.

It doesn't recmp compute until the underlying data changes. RX goes further in Knockout to advanced ways of composing event streams, whereas Knockout goes further than RX into UI development, letting you bind its observables to HTML DOM events and

templates and manipulate them any way you want. RX is great at what it does,

you want. RX is great at what it does, but turned out not exactly what I wanted to build rich UIs, hence I designed Knockout.

This is great.

Um, I don't know. Just

I feel like when I read that that it was like the same thing, you know, like years later. I I think I I had to read

years later. I I think I I had to read that multiple times. I knew it at the beginning and then I think when I tried to build solid at one point on top of RX observables and just expand them because they were going to be built into the

browser as one of those guys who thought like standards, you know, trying to do standards stuff back then about 10 years ago. I think I had to read that again to

ago. I think I had to read that again to remind myself why like they weren't the best fit. Um is it's it's funny you know

best fit. Um is it's it's funny you know this but this is the first suggestion like how it's a very unique or distinct thing. It took some time for us to

thing. It took some time for us to change the name from observables so like RX could keep them and then we could view signals but essentially it's the same kind of mentality behind it. Talked

about API designs, we talked about all this. Have we caught up?

this. Have we caught up?

Yeah, we have caught up. Um, yeah.

No, but browser events aren't stable or is this a remix job, isn't it? Of

course. Too slow sometimes.

It would have been awesome the square cube went in a different hole, but uh Okay. Um do I have anything else? I

Okay. Um do I have anything else? I

think the I think I'm fine with this now. I

now. I there was just this like brief moment in time where I where I I saw a bunch of I I only flagged this one but I saw a bunch of versell related like I think

Karma was one in Malta was another one both being like wanting to remind people that they funded initial like Tanner on his initial work when he started tanstack starter tanstack router he he

wasn't really using start I think as much time he was doing router mostly at the time, but at the beginning of it, like about a year and a bit ago, um Versel actually was the was a major

partner. It was just I think there was

partner. It was just I think there was an interesting tension here on the politics. Um because I was like,

politics. Um because I was like, yeah, was it was it the view post engagement?

Let's see what this is.

National phenomenum. See all these people are like is Verscell gonna buy Tanstack and it's like no since felt now start it's not now this was like two years ago people have no clue

but then there's like this whole political angle this kind of feels like a friend who lends you money when you're down on your luck then brings it up every chance he gets I've seen we're funed hand tech a million times but I

don't see other people who have done the same say this at every chance they get odd that's fair that's that is that's why I bookmarked it there just something that it felt really weird around that time

period. Um, but

period. Um, but whatever. I can't be bothered to care

whatever. I can't be bothered to care too much on the other end. In either

case um maybe it's best that we all kind of stay away from the political aspects. Um,

oh yeah, yeah, Tanstack.

Yeah, for sale share is 5%. So compared

to what others have contributed since it's it's it's it's not that big but like yeah you could see by the the by the like versel fans like reactions to

this where people are like bend the knee like people are treating this like and I I I kind of I saw Tanner actually um

um at US thing. It's like it's not like we people aren't appreciative of the funding and stuff and it makes a huge difference like super appreciative. It

was just um you know sometimes like the because of some of the like hype kind of thing around this. I remember when Verscell first uh funded solid $100 a month which is pretty small compared to

pretty much everyone else they've ever funded but you know they they gave us a small amount which for us at the time was actually a decent chunk for us. you

know, it wasn't, you know, they and they paid that they gave us that for over two years. So, it was it was really thing.

years. So, it was it was really thing.

But I remember like the theing gauntlets like the like Thanos gauntlets like you know Versel and Giamo on this and like the hype thing and it was just so funny cuz the announcement looked better than

the like the reality of the of of the stuff, right? like um it was just it's

stuff, right? like um it was just it's just kind of weird how like the the these narratives start kind of popping

up, you know, like um Yeah. I don't

know. It's funny.

Yeah. Yeah. It's Yeah, it's funny. I

I've I've seen that. I've seen this before and yeah, TANSAC is very widely um you know there's sponsors. I I need to do a better job

sponsors. I I need to do a better job getting sponsors for Solid. I I it's funny every time I talk to people I'm like you guys you guys realize like if we actually had developers the future would be here that much

sooner. The biggest contributors we've

sooner. The biggest contributors we've had over time obviously Netlefi and Sentry paying wages but also from the outside perspective um Google the money

they put into uh that they gave us from the whole uh that program they they did um that went to the research into our server components and into like which

basically created Saravel which is the serializer behind solid and solid start and tan stack start and I think they're even using an Astro now I double check that was actually originally from Google

funding getting an Alexis on there. So

like these things make a difference.

It's just so funny like the server component thing that Tanner's talking about, you know, I' I've been sitting on that for like a year, you know, like and I had other approaches like there

there's I just didn't have the means to finish it at the time in Solid because I had to do other work in Solid. And I

feel like um there's so many things that if we had the same kind of funding or capability, we'd be able to do like it's not from a lack of direction or ideas or

you know a whole bunch of other things.

It just it's just where we are anyway.

Anyway, uh I think we're done. Uh it was a long stream today, six and a half hours, but uh I'm not going to be streaming for the next couple weeks. There's like

Thanksgiving and then some I think my daughter's first uh ballet uh performance for her Nutcracker this year. So, um I'm going to be away for a

year. So, um I'm going to be away for a little bit, but uh I'm glad I got to show what I'm working on. I'm sure by the next time I'll have this all impmented in the JSX and we'll have some really sweet demos to show. But I think

I think it's a really interesting direction to async that we've been taking. And I think I think when you see

taking. And I think I think when you see the pieces together, I think it's I I finally feel like it's it's jelling.

Like there's a lot of tra there's more trade-offs than I would have wanted at the onset, but the end result is much cleaner. And I think this is going to be

cleaner. And I think this is going to be really really powerful moving forward.

All right. Anyways, you all have a great one. Till next time.

one. Till next time.

Loading...

Loading video analysis...