Closed jorgebucaran closed 6 years ago
Deferring can prevent some redundant updates - that's good.
But you're betting on setTimeout()
as a means of deferring updates until hopefully the element is back in a consistent state - if all updates are performed in a blocking manner within the main thread, that'll probably work most of the time, but... you're accepting partial state updates, which means you can still get into a temporarily incoherent state - if you validate the state before you render, and throw an error, the stack trace won't reveal the source of the bad state, so it's not really a good work-around.
It's also not a very interesting example, because count
and title
can't really have conflicting values, so there isn't really a case for incoherent state here.
Simplest example I can think of: a star rating widget with a score
and max
property - it displays max
stars, score
of them highlighted, the rest grayed out.
Case: if max
and state
are both currently 5
, and you set score
to 10
before updating max
to 10 - the state will be temporarily 10
out of 5
stars, which should fail.
The real point though, is that if max
is currently 5
, in a React component, I would throw immediately for setState({ score: 10 })
, which would be an actual error - while updating atomically with setState({ score: 10, max: 10})
is guaranteed to always work regardless of current state.
Presumably, you do see the problem now, right? :-)
My main point is I'm not entirely happy with the internal architecture of custom elements. I know we can mostly work around the ugly and achieve something that works approximately the way we want, under most normal conditions - and as said, I also do understand that it has to work like this, or else they'd have had to change the DOM API itself...
No, I don't see the problem (yet). I find custom elements an adequate alternative to encapsulating what you call control/accidental state that doesn't interfere with state-first/single-state application design.
Here is a star rating widget with a score
and max
attributes just like you described. I'm using radio buttons. I was too lazy to improve the CSS at this time.
There were no incoherent states in the making of this pen.
/cc @zaceno @SkaterDad @rbiggs @mindplay-dk
@mindplay-dk But you're betting on setTimeout() as a means of deferring updates...
We can use an immediately deferred Promise as an alternative to setTimeout like in HAV2, so much room to improve.
Here is a star rating widget with a score and max attributes just like you described
I mean, yeah, you can just ignore incoherent state like score = 8, max = 5
and render it like score = 5
- my point is mainly that no one would do that in a component; you'd throw errors for invalid state. I'd expect any functional or stateful component to throw an error.
So this is a good example to contrast the difference between custom DOM elements and components:
Elements (custom or standard) are just nodes in a document - there is no right or wrong state for document nodes: you can't violate any domain rules, they don't throw errors, they just render the best/closest possible representation of their current state.
Components (functional or stateful) are components of your application - they produce document nodes, but they are themselves software units with domain rules, and they should throw errors when those domain rules are violated.
If all components were implemented as custom elements, well...
Design constraints on elements are much more lax - a well-behaved element, when it's in an incoherent state, literally just has to render some kind of representation, and exhibit some kind of behavior.
Design constraints on software units (components) are generally much stricter, since otherwise you'd get into debugging hell on every project quite quickly: you'd never know when, why or where a bug was introduced - literally you'd have to click through your entire UI and visually test all it's constraints, or write elaborate headless browser tests to see if every component instance behaves well, in every case/context, under all possible conditions, because it'd never throw errors.
Bottom line: I wouldn't want to work with custom elements exclusively in large-scale applications.
Components, on the other hand, can validate and report errors, and work very well at scale.
I'm not saying you couldn't come up with some kind of custom element/component hybrid that does report errors, but again, your stack-traces aren't going to help much, since you won't know about errors until after the fact, when it renders - and it's not how DOM elements are supposed to work.
@mindplay-dk We can do whatever we want, make it throw errors or not, clean the stack traces, make it trigger error events, and so on. You gave me a problem and in a few hours over a few days, I put together some code to show you custom elements can be used as an escape hatch from the strictness of the state-first/single-state purely functional components paradigm in Superfine/Hyperapp.
I think we're done here! 👋
About class components (https://github.com/jorgebucaran/superfine/issues/134), I was thinking, what if we could do something like this?
Just throwing crazy ideas out there?