DEV Community

Discussion on: The Cost of Consistency in UI Frameworks

Collapse
 
webreflection profile image
Andrea Giammarchi • Edited

beside me editing previous post to add another (fair) point ... let me answer the rest:

if you felt it singled out a single solution unfairly that wasn't the intention

all I meant to say is that if you have const [value] = thingy it's not a design decision that value will be the same for the entirety of its existence in that scope, it's simply how ECMAScript defined constants in a scope.

Saying that a constant is different from a property access (Vue) or a function invoke that "who knows what's going to return next" (Solid) is how JS works .. nothing to do with frameworks, hence my question: what were you trying to achieve here? If you wanted to explain differences you did, but it should never have been a competition, imho, as these are the basics of JavaScript, not frameworks.

No idea what you are talking about.

If you calling setCount(count() + 1) updates the DOM element textContent it means you are side effecting synchronously in the DOM world blocking the main thread ... that's what I mean.

The reason uland and React or others return 0 as textContent is because they don't synchronously update the DOM when the state changes, they schedule it, like you said before.

Now, if Solid via tools does some magic vDOM thingy there, OK, I didn't know, but if Solid.js applies state changes synchronously to the DOM it's blocking and blocking is not cool.

Thread Thread
 
webreflection profile image
Andrea Giammarchi • Edited

More explicitly, in React:

const [count, setCount] = useState(0);
setCount(count + 1);
setCount(count + 2);
setCount(count + 3);
Enter fullscreen mode Exit fullscreen mode

will result into a single update with value 3 next time ... with your examples instead, it looks like with Solid, the same operation via count() + x will result into 3 DOM updates instead, no scheduling ... that's slower, and a pattern you chose, not the best one for sure, likely the worst out of the 4 libraries or frameworks you decided to compare in here.

Thread Thread
 
ryansolid profile image
Ryan Carniato • Edited

It is a design decision for me. We have the ability to choose any API we want when designing things. I've hit this over and over. Change it to let if you feel more comfortable but it is irrelevant. This is an over simplified example to illustrate change management behavior.

It isn't a competition because as the article eludes to at the end. I'm actually back here again trying to see if I should revise my previous design decisions here. I may have opinions but this is not saying which framework is better. There is a tradeoff to all of these, and that's life.

It isn't a VDOM thing either. Inferno works like Solid in this example. It is very much a choice.

On the topic of synchronous blocking I want to challenge that a bit. I mean all DOM updates happen on the main thread so this has to be a matter of how much work you do. As I said it isn't that batching/scheduling behavior doesn't exist in Solid, more that there is a question here. Synchronously updating the DOM could be fine if you do basically no work but update the DOM. If someone wrote:

element.addEventListener("click", (e) => {
  e.target.setAttribute("data-clicked", "true")
})
Enter fullscreen mode Exit fullscreen mode

would you get on their case for synchronously updating the DOM? Solid is just a system of events that do stuff.. It runs once and wires it up and then goes and fires. You can schedule those events etc.. but that's it. At somepoint something blocks someone because the work needs to be done. Solid fine-grained just tries to keep that at a minimum always.

Thread Thread
 
ryansolid profile image
Ryan Carniato • Edited

That's the point you are allowed to have your opinion. I'm not going to tell you that ___ choice is worse for uland or whatnot. But you just did. Thank you for your input.

Thread Thread
 
webreflection profile image
Andrea Giammarchi • Edited

Synchronously updating the DOM could be fine if you do basically no work but update the DOM

that's what every framework and library does at some point in time ... but you do it without scheduling updates, and that's an issue because you might involuntarily trigger repaints and reflows while executing JS ... Solid.js here is as bad and blocking as accessing element.offsetWidth could be, because a state can cause other DOM parts to move right away so you'll have, on a complex stack, 10+ blocking things instead of maybe 1 or two, because style changes are scheduled next paint tick anyway, unless you force re-calc there, and Solid.js will never be able to batch (the topic of this post indeed) all changes at once.

You made a choice to use callbacks and you have pros and cons, but it'd be great if you could recognize the cons ... and blocking the DOM per each state change is a HUGE cons to me, and I didn't know, so I was surprised you wrote this as if Solid.js was cooler (I know you didn't mean it ... but you know, you kinda tried hard to justify that 1 2 2 and I tell you, that 1 2 2 can be a real-world performance issue in scenarios textContent is not the only thing involved in the state change).

Feel free to ignore my comment, or maybe rethink scheduling in Solid.js because this thing I've learned today is a pretty bad news to me, something I believe if properly tested in js-frameworks would push it down the slope with extreme ease.

Thread Thread
 
webreflection profile image
Andrea Giammarchi

P.S. custom elements attributes changes, as well as connection and disconnection events, are synchronous and blocking too ... if a state change an attribute and you have a reactive chain in there, for a single state change that maybe involved the whole stack you'll have a clunky experience due blocking and undesired things moved around.

Maybe for 95% of sites out there this is not a real concern, but if everyone else went for a non directly blocking approach when a state gets updated, there's probably a reason behind ... right?

Thread Thread
 
naasking profile image
Sandro Magi

it looks like with Solid, the same operation via count() + x will result into 3 DOM updates instead, no scheduling ... that's slower, and a pattern you chose, not the best one for sure, likely the worst out of the 4 libraries or frameworks you decided to compare in here.

Gotta disagree there. You're effectively saying that given a choice between correctness and performance you should choose performance, without even evaluating whether the correct solution's performance is sufficient.

JS is a wildly mutable language. The contexts in which you might be accessing state are uncountable. Solid preserves consistency of the dataflow graph when accessed from all contexts and is consistent with JS mutation semantics. Therefore it's approach is the least surprising and most flexible, able to slot in where you need it. It is clearly the right default, and should only be bypassed when profiling actually demonstrates a problem.

Thread Thread
 
webreflection profile image
Andrea Giammarchi

given a choice between correctness and performance you should choose performance

I chose correctness like I've already mentioned ... my libraries chose correctness which is the safest bet as the OP wrote.

without even evaluating whether the correct solution's performance is sufficient.

The first version of uhooks was synchronous and it's been profiled, benchmarked and tested until the point it became like React, so that all states that changed in an entire stack call would side effect with a final state once (as effect) and that was both correct, more predictable, but also enables fiber/suspense like patterns but again, effecting synchronously plays badly with Custom Elements and some other HTML or SVG attribute, but also I never talk or expose concerns by accident, too many years on reactive patterns and yes, I made my choice there.

It is clearly the right default

Not to me and apparently not for React neither, where hooks come from. Maybe solid should stop comparing its mechanism with hooks, as it's clearly too different there, for better or worse.