jeswin
10 months ago
I tried to understand the referenced article "Web Components Are Not the Future" - but found that there weren't many convincing arguments.
The current state of Front-end frameworks is an absolute mess. Speaking for myself, I don't want to learn a complex framework. I don't want to learn magic that I don't understand without reading the documentation (useState, createSignal et al). Magic in frameworks is often a hack, unlike magic in libraries. The first library I used was Prototype. It felt like magic, and it truly was. And so was jQuery, and Backbone. I never had to guess what "useState" does behind the scenes.
There are many things which don't carry over into Web Components from current JS frameworks. But if you start from Web Components (ignoring everything you know about frameworks), it suddenly becomes intuitive. And it brings in abilities which are missing otherwise, such as isolation via Shadow DOM. It grows on you.
In my view the only thing we should retain from the React era is JSX (for many reasons, true type-safety, autocomplete etc). I wrote a library last week for using Web Components with JSX. No magic other than JSX. https://webjsx.org
crabmusket
10 months ago
> I don't want to learn a complex framework. I don't want to learn magic that I don't understand without reading the documentation (useState, createSignal et al).
I can't really parse this sentence. It seems to have a lot of ideas in it. Do you want to learn a framework at all, or have one that is so magical that it feels like it doesn't need to be learned? Do you want to read documentation or not? Do you think the problem with React is that its primitives are unsuited to the work you do in it? Or to the work anybody needs to do?
I've spent most of my professional career in Vue, so I don't have a great perspective on the React ecosystem. But Vue feels like it must be included in your "complex framework" statement. I've definitely felt some pain from overuse of the framework, or poor understanding of various features, libraries, etc. The ecosystem around full-on SPAs is indeed complex. I'm just not sure what other systems would let me personally, and us broadly, manage a complex stateful client-side app.
(This is entirely separate to overuse of SPAs for things that shouldn't be SPAs.)
eddd-ddde
9 months ago
I think the point is that frameworks ' magic isn't 100% there yet. You eventually HAVE to dive deep and understand things about the implementation to understand how to use it.
AlexErrant
9 months ago
Ryan builds out Solid's reactivity system (createSignal) from scratch in about 20 minutes, live, in this video https://youtu.be/N-Y32BqhoYQ?t=1100
I haven't bothered fully grokking it because I've never had to understand the impl details. Solid gives me literal dom elements, and that's low-level enough for me.
ruszki
9 months ago
I’ve never seen a framework or even languages into which I don’t need to dig deep from time to time. It seems to me an unachievable high bar.
hu3
9 months ago
I'll try to give an example of "bad magic".
Did you know React renders twice in developer mode to try to expose bugs with side effects?
If this doesn't raise an eyebrow, I don't know what will.
jemmyw
9 months ago
That seems like a pragmatic solution. The point of having a dev mode is to help development and catch mistakes. if(devMode) { rerender() } doesn't seem like magic. Though in general I really dislike the term magic for what is just code doing something.
hu3
9 months ago
Humans have limited cognitive capacity (and time).
To me magic code is code that requires a significant level of cognitive investment to understand and keep in your brain RAM. That threshold varies between people but it's always there.
In React's case, the chosen solution is not the issue here. It's a symptom of bad architecture. The library should be doing more than rendering twice to protect developers from side effects, to a point that rendering twice wouldn't be required.
That feels as bad as rebooting JBOSS servers once a day to "fix" OOM crashes. It's a hack at best and doesn't fix the real issue.
jemmyw
9 months ago
I disagree. React is saying that you need to pass it a function for rendering a component and it does not guarantee how many times that function will be called. There are documented, well defined ways to call side effects based on component lifecycles.
However, how can react know what a side effect is? Hook into well known ones by hijacking the browser API? That sounds like a bad idea. Provide their own linter/compiler. That seems on the radar but I'm not sure I like the idea.
Also react doesn't stop you from doing it. You can say nah it's fine I want my side effect. It just runs the render explicitly twice in development, something that could happen in production for various reasons, so you can see what will happen.
Your proposed solution isn't very practical. A better solution would be a guarantee that render will only run once. But that's not how react has ever worked. There are other frameworks that do that. As with anything, there'll be a trade-off.
edflsafoiewq
9 months ago
> The library should be doing more than rendering twice to protect developers from side effects
Like what?
bryanrasmussen
9 months ago
probably the parent poster does not use React so it would seem a heavy demand on a human to make, given the already stated limited cognitive energy and time.
I suppose I would think not rendering twice and some sort of warning about side effects would be beneficial, rendering twice means that you get a misleading view of what your application behavior is, I can see how people would - from an architectural perspective - consider it bad without necessarily using the framework.
kaoD
9 months ago
> some sort of warning about side effects would be beneficial
Rendering twice is exactly what allows you to detect that. How would you detect a side effect if not by calling the function twice?
React's contract is that your component should be allowed to render twice without any changes so this is just upholding the invariant in dev mode.
spion
9 months ago
You can use a language / compiler / static analyzer that restricts side-effects.
kaoD
9 months ago
Funny you mention that https://react.dev/learn/react-compiler
user
9 months ago
hu3
9 months ago
I do also use React, unfortunately.
bryanrasmussen
9 months ago
my mistake, I feel your pain.
Daishiman
9 months ago
Things like validating or limiting possible React code you can write such that these effects are impossible, in the same manner that abstract data types in programming languages attempt to define data structures that are correct by construction, or the same way that reactive programming enforces a programming paradigm that attempts to minimize unwanted interaction glitches.
hu3
9 months ago
If you have to ask.
Learn Elm and you'll see React's shortcomings clearer. They don't render twice but that is just the tip of the iceberg.
Be warned though, exiting the cave is painful.
jemmyw
9 months ago
I've used elm. It's not that great. In many ways it has the same shortcomings as react but far worse. That is you find yourself wanting to do something as yet unsupported (which we often do because otherwise why write new software in the first place) you have to break out of it's abstraction. Except doing so is 10x harder with elm, and the community around it is so much smaller you can't find the answers. Also, after I personally had moved on, there was something of a tension between the community and the authors. Maybe that's resolved, although I'd suspect for some the resolution was to no longer be part of it.
CharlieDigital
9 months ago
It's because the fundamental model of React's render cycle is unintuitive when combined with state. It's easy to make mistakes of this class specifically with React.
mpweiher
9 months ago
> That seems like a pragmatic solution.
That's not a contradiction to it being bad magic.
In fact, this being a pragmatic solution is a strong, though not conclusive, indicator that the underlying abstractions are not fit for purpose.
And the fact that lots of pragmatic choices led to those abstractions that are not fit for purpose also is an indicator that something about the starting point or the road is not right. Or both.
jemmyw
9 months ago
> abstractions that are not fit for purpose
You say that, but react is very successful, indicating that it's abstractions are working just fine for many people. Maybe we'd say they're not perfect but they fit it's purpose. It might not be my favourite frontend library to work with, but it's the one I'd be most likely to choose for commercial work because it does work well, and high use means that people have explored many solutions to problems with it.
mpweiher
9 months ago
You missed "underlying" from "underlying" abstractions.
React is an implementation, not the underlying abstraction. With react it's not even clear what the underlying abstraction is.
Guillaume86
9 months ago
Why do you care? Or are you just against the general idea of a framework having constaints that are a bit unusual for their language, like "components must be pure"?
kaba0
9 months ago
Why would that be bad magic? It’s a very clever way to expose stuff that is accidentally side effecting.
c-hendricks
9 months ago
It doesn't though. StrictMode does, and that's optional.
szundi
9 months ago
I think he was pretty clear that the "magic" in frameworks is not something you can easily understand, therefore have to guess how it really works. He doesn't like that.
jemmyw
9 months ago
You don't need to guess. You can actually read the code! Not saying that you should straight away when learning, but later, when you're familiar with your framework, I think reading through the codebase and understanding it is good practice.
cj
9 months ago
You can read the code, but it’s complex and convoluted.
He referenced Backbone as a comparison point. If you compare Backbone’s source code to React’s source code, you’ll get what he means.
Basically, libraries like Backbone are small and simple enough that you can literally read the source code and fully understand how it works. Compare that to React, where the source code is an order of magnitude larger and very difficult to fully grasp the inner workings.
The simplicity and ability to easily understand the source code obviously comes with tradeoffs (e.g. with Backbone, to use it to build a reasonably complex app, you basically have to build your own framework on top of it, compared to React which has more abstractions and therefore is more plug and play.
jemmyw
9 months ago
It's complex but not that convoluted.
spion
9 months ago
IIRC reading the React source code became quite a feat around the time fibers were introduced.
redman25
9 months ago
I've found the Vue community to be a little better at managing complexity than the react community has mainly because Vue was originally touted as a solution to some of react's problems. People are more conscious of the tradeoffs.
mpweiher
9 months ago
> Do you want to learn a framework at all, or have one that is so magical that it feels like it doesn't need to be learned?
My view is that the problem domain is not complex enough to warrant the complexity of our "solutions".
See also: https://www.youtube.com/watch?v=ubaX1Smg6pY
Is it really "Complex"? Or did we just make it "Complicated"?
rty32
10 months ago
One aspect of this is how you think about UI. The underlying pattern of jQuery is fully side-effects -- you select an element and make some changes to it. Frameworks like React and Vue.js allows to create UI components whose states are completely determined by data, i.e. what the UI looks like is the value of a pure function, mathematically speaking. It also updates the UI with minimum DOM changes when the data changes. (Although you don't have to make them pure, and arguably you can achieve the same thing with jQuery.) Depending on where you are, it makes UI widgets much more readable and maintainable. These frameworks are innovative in terms of state management compared to "old approaches" (of course, with additional benefits like reusability etc)
Bear in mind that today's websites and web based desktop applications are much, much more complicated than two decades ago, and has a much higher requirement for scalability and maintainability. If you just want to create simple UI, indeed they may not be your best choice.
jsyang00
10 months ago
You do not need to know how `useState` works to understand how to use it to write a React application, it is fairly intuitive to understand how to apply the pattern.
If I look at your library, it seems to me like it requires a much more complex mental model to begin to use.
Of course, it is better in theory for a developer to thoroughly understand the details of their framework, but empirically, React has been very successful in allowing people to build relatively sophisticated applications while understanding very little of the underlying model.
InsideOutSanta
9 months ago
"You do not need to know how `useState` works"
I feel like you eventually do. The issue with React, at least in my experience, is that it's a type of abstraction that seems ill-suited for how the web works under the hood, so it's incredibly leaky. Everything seems to make sense initially, and you get along just fine, but then you run into an edge case, and there's an official workaround for the edge case, but then you run into edge cases for the workaround for the edge case, and suddenly, that's your whole life.
Before you know it, you really do have to know how things actually work under the hood.
dartos
9 months ago
I thought pre-hooks react provided a really nice and simple abstraction over how the web works.
FRP is a nice fit for the kind of UI that makes the majority of the web.
Hooks ruined the framework imo. Confusing api (useState returning an array for example).
Having a class component with hooks for lifecycle behavior made perfect sense. Each component’s state being a field on those classes was easy to understand.
Hooks came out of left field and made everything more complex for the worse.
kaoD
9 months ago
> Hooks ruined the framework imo. Confusing api (useState returning an array for example).
It just returns a tuple. That's not confusing at all and it's a very well established pattern in most modern languages.
If there's anything that can be considered complex and footgun-y in React it's useEffect because most of the time you shouldn't use it at all but it can be abused very easily and it kinda works even if you abuse it (but introduces a huge maintenance burden).
dartos
9 months ago
> It just returns a tuple. That's not confusing at all and it's a very well established pattern in most modern languages.
A few things wrong with this. It does not return a tuple, it returns an array with 2 elements. You, as the react dev, need to just know that this is the case and that one is the value and the other is a set function.
In most modern languages, tuples are common, yes. But not in JavaScript. React isn’t a python or go framework, it’s a JavaScript framework. Why doesn’t it act like almost everything else in js land and return an object with 2 named fields? Why place extra knowledge burden on the developer? It’s just poor api design
Yes useEffect is also a huge complex pain point, but it just takes longer to type out why that is.
Pretty much all the hooks are as almost nothing else in the JavaScript ecosystem acts like they do.
xpl
9 months ago
> Why doesn’t it act like almost everything else in js land and return an object with 2 named fields
The explanation is actually very simple: because in 100% of times you need to give those two fields custom names. It is easier and more concise with tuple:
const [text, setText] = ...
Than with object + renaming, which quickly gets clumsy when you have dozens of such lines in your component: const {value: text, setValue: setText} = ...
dartos
9 months ago
That’s not a good reason.
Especially in our world where strong typing is something preferable.
Fewer characters at the cost of clarity is poor api design. Implicitness is almost always worse than explicitness.
Explicit !== clumsy
And again, almost nothing else in the js ecosystem behaves like this. Especially at the time of the big hooks update to react.
Also, again, it’s not a tuple. It’s an array with 2 elements. JavaScript does not have tuples or the semantics for interacting with them as such. You just need to know that there’s always going to be 2 elements.
That extra knowledge burden is the hallmark of poor api design.
xpl
9 months ago
> Also, again, it’s not a tuple. It’s an array with 2 elements. JavaScript does not have tuples or the semantics for interacting with them as such
Not true. In TypeScript, there are tuples — you can perfectly describe an array having 2 elements with different types, and even give names to them:
type KVPairTuple = [key: string, value: number]
We use it all the time for simple 2-element thingies. You can say JavaScript isn't TypeScript, but cmon, just everybody out there uses TypeScript, it is the basic norm nowadays. So we're really talking about TypeScript semantics here.Also, even JS uses tuples for its core APIs. Enter `Object.entries` and `Object.fromEntries` — they operate on kv-pairs in form of 2-element arrays. So your assertion that tuples are something alien to JS ecosystem isn't accurate simply because of that.
dartos
9 months ago
> Not true. In TypeScript…
Not talking about typescript.
Typescript wasn’t nearly as wide spread or as complete back then anyway. Facebook was still on flow.
> they operate on kv-pairs in form of 2-element arrays.
So… Not tuples…
> So your assertion that tuples are something alien to JS ecosystem isn't accurate simply because of that.
My words were “almost nothing else.” I’m sure someone somewhere uses the idea of tuples in their js code (implemented as arrays, ofc) but it’s extremely far from the norm.
Also none of that refutes my point that it’s poor api design. Thanks for being pedantic tho.
kaoD
9 months ago
> Not talking about typescript.
TS is just encoding JS semantics into a type system.
A function returning a fixed-size array in JS is effectively returning, semantically, a tuple. They're just not a different type unlike in other languages (for different reasons).
JS arrays are not even arrays since they (1) are not contiguous and (2) do not require items to be of the same size (typed arrays are actual arrays though) except by their backing implementation (which uses js vals, but that's a property of the implementation, not the language). They're sparse vectors. But nobody cares about that technical distinction and we still call fixed-size arrays tuples and variable-size arrays arrays. You can even attach properties to them because arrays are not vectors, they are objects. Or can be, for that matter. The backing implementations are complex and very dynamic.
JS was intentionally made this simple so it could have emergent semantics. Scheme-ish.
> Typescript wasn’t nearly as wide spread or as complete back then anyway. Facebook was still on flow.
It was when they introduced hooks.
dartos
9 months ago
That’s a lot of words unrelated to my point about the API being poorly designed.
Typescript is irrelevant.
The implementation of arrays in js is irrelevant.
Js being intentionally simple is irrelevant (and might even strengthen my point)
xpl
9 months ago
Your very definition of "poorly designed" is overly rigid and unproductive. When you design APIs for everyday human use, you value expressiveness and succinctness over verbosity and explicitness. Because such APIs are more of a "human interface" (like UI) than a "program interface" in a sense.
One thing is some random payment processor API that you encounter only once in your career (it doesn't need to be terse and it is better to avoid any magic here) — and whole another thing is stuff like jQuery or React, which I can produce/read in thousands of lines per day. You would design such APIs with different objectives, like being easy to type, easy to read (once you know the API).
The mantra "explicit is better than implicit" is wrong, because it really depends.
xpl
9 months ago
> Yes useEffect is also a huge complex pain point
We have a rule of thumb in our projects: if you use useEffect directly in application code, it is a probable sign that something is wrong with your code, like you're working on a wrong level of abstraction. Almost every direct use of useEffect is better solved with some standard hook from a popular library (like react-use or whatever you like — there are plenty of them).
Like, binding event listeners? useEventListener
Network/async calls? useAsync
timeouts/intervals? useInterval, useTimeout
And etc. etc.
useEffect is really a low-level building block for library code and we rarely use it directly, as it is unsafe and hides the original intent. Much like `new` and `delete` in C++ — you don't use it directly, there are smart pointers. Library hooks are your safe smart pointers over useEffect.
com2kid
9 months ago
React + classes made sense. Redux was hard to use. All react needed was a simple state management solution that didn't take 500 loc across multiple files and a ton of useless object copying to make a page full of form elements work.
Instead it got a complete paradigm shift to a leaky abstraction. Not that the previous abstraction wasn't leaky, it was alwayz super easy to have components re-render when not necessarily.
ljm
9 months ago
There's a world where browser UIs are programmed in Smalltalk instead, which I think is what the authors of the DOM may have intended when building it out OOP-style.
It would bear almost no resemblance to the web we have today, but message passing between UI components throughout various parts of their lifecycle has been a great way to model an interface for decades. You only need to look at the overall fit and finish of a typical MacOS or iOS app, with Swift simply pulling Objective-C into the 21st century.
dartos
9 months ago
Web UIs tend to make heavy use of message passing via event listeners.
The major difference between web UIs and desktop apps is two fold. In web UIs, you don’t generally have an event loop in which you change your app state based on system input events and there is, generally, a slow request/response cycle for any interaction.
That’s why immediate mode UI doesn’t really fit well in web land.
djbusby
9 months ago
Seems like that happens with every frameworks I've ever used since 2000 (in Perl, PHP, Ruby, JS, etc). Every framework makes the easy things slightly easier, the boring stuff is included and you get to focus on the fun/hard part - and I think then, naturally, you bump into the edge. But! You get to that point faster. And then you have to know the guts to solve the issue the "framework" way or do some lower-level shit-hack.
I feel like it's just a natural law of any general purpose framework.
It made the first 80% of the job easy. Now you just have to finish the other 80%.
recursive
9 months ago
This hasn't been my experience at all. The implementation details even leak into this crazy thing called "the rules of hooks". It looks like a function but it's actually this new thing called a hook. Which state will you get? That depends on whether the reconciler considers this invocation to be a mount or update. Getting the wrong one? Try restructuring your elements or adding or removing a "key" attribute.
People tolerate this because they learned it but I don't think there is anything essentially simple about it.
phist_mcgee
9 months ago
If you have an understanding of closures, hooks are quite intuitive.
recursive
9 months ago
I have a pretty thorough understanding of both. But I can't understand how you'd find them to be similar in any way. Functions forming closures can be called conditionally, in a loop, or even when no react component is even rendering. Most of the complexity of hooks is not addressed at all by closures, and I don't really what part of their behavior is related at all. Maybe just that you can pass a value to one function, and then get it returned from another one.
The standard hooks delegate to a dispatcher, which has access to the current fiber. The current fiber has a linked list of memoizedState for the current work node. It's true that a lot of the functions that eventually service the hook calls do contain closures. But that doesn't seem to grant much insight into how to use them or how they work.
It's like saying "if you have an understanding of loops, the reconciler is quite intuitive". I mean yes, the reconciler uses loops. But the behavior of reconciliation may still be quite mysterious.
kaoD
9 months ago
I'll try to fix the comment you're replying to:
I think of React components as not closures but coroutines (and hooks are its yield points).
Hooks are implicitly keyed by index which is the most magic-y/surprising part... but I'm sure if you had to manually key them that'd be criticized too (and would be abused to death-by-bugs, so I can see why they went with this design).
If you understand both points above, you understand hooks.
I still fail to get the (usual) criticism of hooks. They have lots of warts but the API (which is often what gets mentioned) is the most superficial and less annoying criticism. Feels like something that would be mentioned after just skimming the docs. Very shallow.
On the contrary: useEffect is a footgun and deserves criticism. useRef being overloaded to mimic instance variables is confusing for newbies (but this is just a naming issue IMO). The difference between normal/layout/insertion effects is complex and subtle. The new stuff that tries to solve some issues with the concurrent mode (like transitions/deferred value/etc.) feels like a huge hack.
React 19 will come with its own warts (actions, RSC...)
But the API? I don't care at all. Pretty simple, at least for my mental model.
com2kid
9 months ago
The complaint is they prior to hooks react didn't have any of this complexity. It was pretty simple to understand. Class components works mostly as you expected them to. There are a handful of things that were really hard to do with class components that hooks + function components made easier, but lots of other things became more complicated with each new set of features react has added since then. At this point the solution to "class components are complicate" is far more complicated than class components ever were.
kaoD
9 months ago
I understand the complaint but my point is that, in my experience (which admittedly might be biased), the complaint usually does not resonate with anyone that did actually use React for at least a moderately complex app.
Hook's API is not perfect but it's a good-enough abstraction that allows the user to have even better abstractions and separation of concerns.
Actual React users did not care about that because the pragmatism far outweighs the theoretical ugliness... which honestly is not even that ugly if you have a mental model similar to coroutines (of course if all you do is OOP a class will look better to you...)
I have recently been fixing some stuff in my old React pre-hooks code and I hated it because class-based components had all sorts of concerns intermixed on their lifecycle methods... no matter how much you tried to abstract them.
Abstracting those into reusable hooks was a breeze and made everything much easier to follow and maintain.
Hooks are far better from a pragmatic point of view.
> There are a handful of things that were really hard to do with class components that hooks + function components made easier, but lots of other things became more complicated
Like what? Does not match my experience at all.
com2kid
9 months ago
> I have recently been fixing some stuff in my old React pre-hooks code and I hated it because class-based components had all sorts of concerns intermixed on their lifecycle methods... no matter how much you tried to abstract them.
The lifecycle concerns are still there, sometimes things need to happen when a component is first displayed, and sometimes things need to happen with a component is removed from the page. It is just handled differently now.
My other issue with hooks vs classes is that, and I say this as someone who loves FP, the best application of OO programming is for UIs. At the base level, a text input field has an object created in the browser, and that input field has state. UIs are inherently stateful things. The OO model is natural for building UIs, you typically shove an object on the screen, that object has some state, and the user manipulates that state.
OO is a great abstraction for UIs. IMHO it is a pretty bad abstraction for most other problem domains, but for stateful UIs, OO maps pretty darn well to what is actually happening!
I just don't see the benefit of throwing another abstraction layer on top of all that.
One reason I love Svelte 4 (haven't tried 5 yet) is that it is so bloody simple compared to React. After years of programming in React, I was literally 5x more productive in my first ever Svelte project than I had ever been in React.
All I need is a good way to encapsulate HTML components for reuse (which is fundamentally an OO thing, instantiate new instances of a component template!) and a good state management system that pushes state changes out to subscribed components.
recursive
9 months ago
For me, it's not OOP vs functional. I find "functional" to be a misnomer as its applied to most react components. Functional used to have a clear definition about having a stable return value and only varying based on parameters.
However, the same problem started afflicting class-based components prior to the introduction of hooks. When fibers were created, component instances no longer tracked their own state. State was injected into them prior to invoking the render function, based on reconciliation. I suppose even before that the reconciler was still choosing which component instance to render.
But at least components had an identity that could be addressed in application code. Now component identity is effectively the fiber instance identity (or its alternate), which is impossible to get a reference to.
In real life, people really seem to like hooks. I can see some of the benefits they provide over the OOP class-based component model. But I can't avoid also seeing the mental foot-guns associated with it.
The very first time I every tried to write a react app, I got tripped up by this. I add a component that moves around in a parent component conditionally. So I had `const inner = <Inner />`, and then based on some condition it would be inserted in various places in the rendered parent component.
Of course after much wailing and gnashing of teeth, I learned that this variable declaration wasn't establishing a component identity. It merely creates an "element", even if it has a key attribute. Component identity, as used to retrieve state, is fundamentally tangled up with reconciliation which can only see the final rendered output of a component. No other components can have state, at least as recorded by a hook.
Most people don't seem to have trouble with this, but it's not how I naturally think of things.
kaoD
9 months ago
Unless my memory is very hazy none of that is related to hooks.
Identity in React has always relied on vDOM structure or `key` which was introduced in React 0.4.0 (July 17 2013, <2 months after initial public release).
> For me, it's not OOP vs functional.
Neither is for me. Note I didn't mention functional once.
recursive
9 months ago
> Identity in React has always relied on vDOM structure or `key` which was introduced in React 0.4.0
You are correct. But so, I believe, was I. Apologies for being unclear. vDOM structure is determined based on the return values from render functions. As opposed to the line of code where elements are created. So if you have `const cmp = <Comp />` in a render function, it doesn't have an identity yet. As you note, that will be determined later, sometime after this render function returns. It might not have a state at all. It might even have multiple states. If the current rendering is an update, `cmp` might be a mount instead.
All these determinations are made based on the content (structure and key attributes) of the assembled vDOM and the reconciliation heuristics.
> Note I didn't mention functional once.
I assumed that's the comparison you were drawing with this line. "better" than what?
> of course if all you do is OOP a class will look better to you
watwut
9 months ago
> of course if all you do is OOP a class will look better to you...
Funny thing is, I do not know what coroutines are and have zero experience with them. I am object oriented class programmer who never cared about functional programming.
I figured hooks intuitively and straightforwardly when I had to work with react a year ago. Ok, function with state, but it was easy to read them, imagine what they do and maintain the code. It just seemed as an improvement over the old react to me, despite having no coroutines knowledge.
kaoD
9 months ago
Exactly!
To be honest they're not full-blown coroutines (since the React runtime cannot control when the component progresses) which might be a bit more complex to grasp... but the idea of "yielding control" to someone else (i.e. to React, when calling one of its hooks) is there and as you say it's pretty straightforward.
kccqzy
9 months ago
> because class-based components had all sorts of concerns intermixed on their lifecycle methods
I think this just means your components are too large and try to do too many things. When your components are simple, their concerns are simple enough that they can immediately be understood, even if spread over several lifecycle methods.
recursive
9 months ago
Which coroutine gets resumed by a rendering component is determined by reconciliation. Rendered components themselves have no identity aside from the reconciler's algorithm for equality.
For me, this is the root of the problem. Or one of them anyway.
Hooks are keyed by execution order, but also the reconciler's opinion about component identity, which you can only control indirectly. Fortunately it usually does what you want. Unfortunately it's not all the time.
I feel like I do understand hooks, but it's not from reading the docs, and it's not from using them. I know this is not typical but doing those things didn't seem to illuminate much to me. I would still find them doing things I didn't want that I couldn't explain. It was only after reading the source that I feel like I understand the model. And personally, it's not one I would use by choice. I can do it if I'm required by a team I'm on. But for me, there's a mental overhead for "thinking in react". It's not a natural set of constraints for me.
afiori
9 months ago
I think that the clearer way to explain hooks is just referencing how they are implemented.
When a function component is called it is called on a "fiber" a stateful representation of the component instance.
This fiber is available to the hook as if it was global variable that is set before the component is rendered.
This is why you cannot call a hook is a setTimeout or a callback to another component: the global fiber is either unset or has a different value.
The other part is that each hook invocation works on a state accessed as sorta fiber.hooks[index++].
So for example you can call hooks in a loop or in conditionals or in synchronous callbacks, but each rendering must be compatible with the first.
Eg
let s;
If(Math.random()<0.5) s=useState({});
else s=useState([])
Should work.You could also do the same with useEffect if you keep the length/nullness of the dept array.
8note
9 months ago
Ive probably been doing it wrong, but isn't useEffect needed to make any hooks work? useState does nothing most of the time
imtringued
9 months ago
Hooks have very little to do with closures.
The key aspect of hooks is that what you are doing is something like this:
function(context) { context.useState() }
Where context is a variable that stores all the hook related data, except in reality that variable is a hidden global variable and useState() accesses that variable internally.
Yeah, they added hooks as global functions so that they look like a "cute" DSL. It saves you the effort to type c.useState instead of useState I guess.
The above code is just for illustrative purposes to get the idea across, according to other commenters the internal implementation has changed from what I remember, but the principle is still the same. Global functions demand global state.
bakugo
10 months ago
You don't need to understand how useState works if you're writing a page with a button that increments a number when pressed, from a beginner's tutorial.
As soon as you work on any remotely complex codebase, you will run into problems that require a decent mental model of the underlying "magic" to properly understand and solve. "Building sophisticated applications while understanding very little of the underlying model" is how you end up with gigantic piles of unmaintainable spaghetti code full of awful hacks, which seems to be the standard for React applications.
lolinder
9 months ago
Is this less true of Web Components?
I've worked with a lot of different tech stacks over my career and every single one of them has required understanding the internals once you start using them seriously. I haven't found React to be substantially worse for that than any other tech stack I've used.
peebeebee
9 months ago
With webcomponents you are pretty close to the “metal”. If you know how to write good vanilla JavaScript, you can take most of that knowledge into webcomponents. You only need to learn the custom components lifecycle, and shadowDOM, which is knowledge about web-standards. With other frameworks you need to learn template syntaxing, how state propagates, how the compiler works, etc etc. Lot of that knowledge might be obsolete in 10 years.
Which isn’t to say it can’t be worth it. Learning multiple frameworks and libraries is also very helpful to skill up because you are learning about different concepts and implementations.
Narhem
9 months ago
Another advantage of web components is the syntax is similar enough to Java (especially with JavaDocs) switching between coding a Java spring backend and a Web component based front end is doesn’t need as much of a mental context switch.
azangru
9 months ago
While you do not need to understand how useState, or any other hooks work, you do need to know that this piece of code will behave differently from the rest of your javascript. Painfully, when the calling of (most of the) hooks is concerned, React takes away from the developer the ability to write conditional logic. This is both unintuitive and bonkers, and it requires the developer to come up with convoluted techniques for working around this limitation. This is part of what 'understanding of how hooks work' means.
jeswin
9 months ago
> If I look at your library, it seems to me like it requires a much more complex mental model to begin to use.
How so?
It has two functions:
(1) createElement(jsx): Allows you to use JSX to write HTML markup. Returns Virtual Nodes.
(2) applyDiff(parent, vNodes): Merges Virtual Nodes created with JSX into the real DOM efficiently.
This is all you need to know. I can keep it simple because I am not doing much in the library. I felt that if I stayed close to the standards, I wouldn't need to do much.
BoorishBears
9 months ago
Maybe you have the luxury of users who want applications that have all the reactivity of a DMV form, but in my apps at some point I'll need the very simple priciple of "do something complex when this value changes" and reimplement useState/useEffect in an ad-hoc manner anyways.
I'm more of a backend/embedded developer than a web developer and I still honestly don't get how people find useState/useEffect as intimidating as your comment makes them out to be.
_heimdall
9 months ago
There are a lot of footguns in react if you don't know how use state works.
If you don't know what triggers a re-render you can end up in a state where the data was changed but the UI didn't update, or where the data changed once and re-rendered multiple times.
In my experience the issues are more noticeable with async state changes, like making network requests or state-driven animations.
bvrmn
9 months ago
Aha-ha. Devs constantly try to use dynamic hooks. For example conditionally rendered component which allocates a hook. Yes, React would trigger a warning, that number of hooks was changed. But this implementation detail requires you to have at least a mental model of what hooks actually are to avoid gotchas.
EMM_386
9 months ago
> The current state of Front-end frameworks is an absolute mess. Speaking for myself, I don't want to learn a complex framework.
It's really not that hard. I was able to pick up Angular to a level where I could create complex sites with it, or submit acceptable PRs that involved in, in week or so.
Granted, I am an experienced developer (C# since beta, HTML/JS/CSS from the start) but it seemed to just make sense quickly.
So when I was asked by a company to replace their aging, complex portal to manage critical infrastructure, I chose Angular for the front end.
That was smooth sailing. It was stable, performant, looked good and everyone was happy.
People often avoid it because it has a "steep learning curve" but that mainly seems to come from developers who came into the industry knowing only JavaScript and maybe a little React. If you are more experienced, you can pick it up right away.
And it helps, a lot, to use such frameworks on large complex sites. For various reasons.
jeswin
9 months ago
It's a libraries vs frameworks thing. Libraries are relatively safer.
Frameworks in C# are slightly better (compared to those on JS), because there are blessed Frameworks and most people are using them. In the JS world, you can see very popular frameworks (with millions of downloads) get abandoned. Not saying that all is well in the .Net world; desktop frameworks are an example. But overall it's a bit different because one company more or less controls it.
edwinjm
9 months ago
To be productive in Angular, you also have to know RxJS, which comes with twenty or so functions you have to become familiar with and with some peculiarities like hot and cold observables. So, no, Angular is not easy to learn.
chmod775
9 months ago
> I don't want to learn magic that I don't understand without reading the documentation (useState, createSignal et al).
Really now. Most devs who think to themselves "man I wonder how useState works internally" will arrive at the logical and correct answer within seconds. It's not complicated or magic. There are bare-bones implementations of react hooks (-ish) with a couple hundred lines of code. Implementing a basic "useState" and "runFunctionComponent" is easier than most third-semester CS assignments.
If that's the bar for magic, I'm surrounded by 20th level Warlocks coming up with new Eldritch Invocations for fun over breakfast.
spion
9 months ago
> Implementing a basic "useState" and "runFunctionComponent" is easier than most third-semester CS assignments.
I'm not sure it is. There is a global dispatcher that finds the right component state to use and increments a counter to ensure that the correct state "slot" for that component is used. There are also a bunch of mechanisms to prevent slot mismatches. I guess you could make a loose analogy with writing custom allocators, except instead of the binding knowing the address, the order of calling useState determines the address :) Really not that simple.
chmod775
9 months ago
> I'm not sure it is. There is a global dispatcher that finds the right component state to use and increments a counter to ensure that the correct state "slot" for that component is used.
Explicitly not part of that proposed task. We're talking about a basic hooks implementation with useState here, not how react deals with its tree of components.
For the sake of the task the signature of runFunctionComponent just needs to be
runFunctionComponent<P, R>(fc: (props: P) => R, props: P, hooks?: any[]): { hooks: any[], returnValue: R }
or even dumbed down to runWithHooks(runFC: () => void, hooks?: any[]): any[]
where runFC would wrap the call to the function component to pass the appropriate props and store the return value, freeing students from thinking about that. Also specify the function doesn't need to be re-entrant.In either case it won't need concern itself with what the component returns (children, whatever), matching children to tree nodes, or scheduling, at all. Would be nonsense to cram that logic in there anyhow.
What you were talking about would make a good later task: easy to get a basic implementation, but hard to get an implementation that isn't subtly wrong in some way. Plus you can slap on extra goals like supporting keys. Lots of room to score students beyond just pass/fail.
imtringued
9 months ago
>Most devs who think to themselves "man I wonder how useState works internally" will arrive at the logical and correct answer within seconds.
The answer is shockingly dumb. To be fair, I checked the code years ago, but basically almost every hook calls useReducer internally and useReducer uses an array stored in a global variable that is set before your component code gets called and the order of the hook calls determines which hook gets what useReducer state.
It's basically a giant kludge and the React developers and users pat themselves on the back how "functional" their components are, when in reality they are flinging global mutable state like crazy.
chmod775
9 months ago
> It's basically a giant kludge and the React developers and users pat themselves on the back how "functional" their components are, when in reality they are flinging global mutable state like crazy.
This is true for literally every useful computer program ever. At some level it operates exclusively on global mutable state. Doesn't mean your high level programmer-facing interface has to look like that though.
kaba0
9 months ago
Haskell compiles down to a C “subset” called C-, and flings mutable state and memory like crazy. That’s the whole point of encapsulation, if the abstraction is sound then it absolutely doesn’t matter that react uses global state — like how else would they do it with this user ergonomics? Using JS is a given.
zelphirkalt
9 months ago
Hundreds of lines of code?? That sounds like way too much complication for something like that, tbh.
kaba0
9 months ago
Heh? My smallest hobby project that is not a POC but actually is finished and is doing something is like 1000 lines long. There are very few stuff you can do with less than 100 lines.
(Just for completeness sake, Haskell and alia sometimes might get away with less lines, because they tend to be “wider”. Word-count is a better metric here)
chmod775
9 months ago
If you want to be at least sort-of react hooks compatible, there's a bunch of hooks you need to implement.
InsideOutSanta
10 months ago
I'm building my most recent project with web components + htmx, and it's mind-blowing how much better all of this feels to me than the typical React/Angular stack. I think there's a place for React and Angular and technologies like them, but 90% of the projects that currently use them would be better off with a much simpler stack.
DimmieMan
9 months ago
I have a growing belief the advantage the advantage you're seeing is more HTML first *culture* rather than HTMX itself, I feel the same way using SvelteKit.
For example, you submit a form with a couple extra tags on a stock HTML form, do some processing server side and swap out the form (or redirect or whatever). No overriding the on submit callback, no having to wire up a validation hook, no having to think about where things are running.
React and angular have a very "let's solve this in JS" culture that creates ultimately unnecessary complexity demons for that 90%.
LegionMammal978
9 months ago
On the other hand, I've recently been helping someone out with their messy SvelteKit website, and I've personally found the framework horrible to learn. The routing and rendering logic is all diced up between +layout.ts, +layout.svelte, +page.svelte, another +page.svelte, and a few other .ts and .svelte files scattered around lib/, to the point where I can hardly understand what data is going where, and which parts are rerendered when that data is modified. Also, prerendering has bitten me with odd discrepancies between localhost and production.
While this messy project likely isn't the best showcase of SvelteKit, I just haven't experienced its alleged simplicity: there are too many files with special roles, and too much magic transforming things behind the scenes. I'd take React over this any day, where the components form a simple tree, and the dependencies are (often painfully) explicit instead of being swept under the rug.
DimmieMan
9 months ago
You know I almost didn't mention svelte in passing to ward off this type of comment... Replace svelte and react with any framework and you can a thousand arguments of the same damn format and probably a couple in this thread, It was tangental to the point.
One possible advantage of something like HTMX + web components I guess is splitting things into a million files all over the place that can fetch data and manage their own state is painful which seems to be how most svelte/react/whatever disasters are made.
There's plenty of ways to make a HTMX disaster but the culture and methodologies being pushed are all leading towards simple, HTML first design which I believe might be the 'secret sauce' rather than the technology itself.
LegionMammal978
9 months ago
Sorry if I sounded rather cliche. What I was trying to get at is that my #1 concern will always be data flow: if you can't easily understand what affects what else and how, then you'll end up with a huge mess of edge cases that will sink your website. And whether a framework is 'HTML-first' or not seems to be mostly orthogonal to this issue, as far as I can tell. Parts of Svelte are guilty (IMHO) of opaque data flow, and so are things like Redux built on top of React.
That is, the way I see it, a tree is a tree, whether it's superficially written in JSX or HTMX. But of the ways to move data up and down the tree (and/or modify the tree itself), I prefer the explicitness of pure React over the magic of many of its competitors.
wruza
9 months ago
I feel exactly this about everything in modern programming. It’s almost a generation thing. Files over files over files. Half of a file is imports, another half is an ad-hoc boilerplate with a single line of action code. What could be a page of code is now a folder subtree with a bunch of whatever.
It’s like they all read some shitty book similar to that one about OO patterns.
troupo
9 months ago
> No overriding the on submit callback, no having to wire up a validation hook, no having to think about where things are running.
BTW, forms are broken in Web Components. From needing to wire them manually with Javascript via Form Data to custom submit buttons not working in forms (will be solved with another Javascript-only spec maybe in the next ten years)
meiraleal
9 months ago
> In my view the only thing we should retain from the React era is JSX
honestly lit-html is much better and based on existing browser APIs. We should make it part of the webcomponents spec! Which is a work in progress:
troupo
9 months ago
> lit-html is much better and based on existing browser APIs.
Ah yes. A new framework with its own custom DSL, its own custom hook, sorry, "directive" rules, it's own incompatible flavor of SSR is definitely the way to go, and whould be a part of the standard unlike Polymer before it which was also touted as the bee's knees.
> We should make it part of the webcomponents spec! Which is a work in progress:
Whatever the outcome of that discussion, it won't be lit.
mock-possum
9 months ago
Have you tried the Lit library? Using lithtml to write web components based on Lit Component is DREAMY imo, if you’re into web components. It really reminds me of using jquery’s helper methods for ajax - like why wasn’t it just this way by default all along.
jdmg94
9 months ago
I work with web components within a FAANG company, it was a huge mistake and everyone hates it. If your argument for web components is that they're "so intuitive you don't have to learn" then you're lying to yourself.
coffeefirst
10 months ago
Yeah. I know React quite well, there are legitimate use cases where it shines, but...
What we've lost is the ability to say "let's make a website today" and just start making UI without build tools or crazy install trees or massive libraries that need maintenance and security updates, and drop it on a server somewhere.
I keep thinking I can have that back... ES6 imports are fully supported now, modern CSS is amazing, all we really need is an SSR/a11y-friendly way to do some kind of nestable HTML macro/component, and we can party like it's 2007 (but with grid, and import statements, and all the other new shiny objects).
lolinder
10 months ago
As I'm thinking about this, the main thing that is left before I could imagine a build-free website/webapp is TypeScript support in the browser. Even just esbuild-style stripping of types would be enough, but I can't imagine bringing myself to write even a small amount of JavaScript without types any more.
Even without that, a tiny system that just depends on tsc should be within reach at this point.
evilduck
9 months ago
I wouldn’t personally make these tradeoffs but for the sake of argument if you're willing to write substantially more type info into JSDocs (AI tooling may alleviate this nowadays) you can retain most of the coverage and assurances without using anything Typescript adds to the syntax superset while still using it for type checking during development. Even without the type-heavy JSDocs you might be able to alter your coding style to lean into easing and increasing inference (more classes instead of types or interfaces) and get pretty far.
Honestly though, I just never really run into use cases where I need to "make a page in a day" and where modern tooling gets in the way. I'm comfortable with create-react-app, NextJS, Gatsby, and a couple other things, I can definitely put a new static asset project from one of those on a VPS by shuffling files over scp in the timespan it takes to make a pot of coffee, and I would strongly prefer having those tools than trying to be "pure" for hand-wavy reasons and unproven benefit.
codethief
9 months ago
> and we can party
You go party but for a large team (or group of teams) I will still prefer the explicitness of data flow and the type safety that Angular/React/Vue/… give me.
stickfigure
9 months ago
As soon as you said "SSR" you've brought in a complex build system and server infrastructure.
But if you just want a simple web page with some javascript or even a react spa, it's not a whole lot of buttonclicks. Super easy to get deployed on something like cloudflare pages too. IMO it's easier today than it was back in the html forms era.
8n4vidtmkvmk
9 months ago
In my admittedly little experience with shadow DOM, it doesn't isolate as much as it claims. CSS variables pierce the boundary, so if your styles are built around that, you can still run into trouble.
I just haven't seen any benefit whatsoever once you have CSS modules. And CSS layers help too.
peebeebee
9 months ago
ShadowDOM, and by extension web components are great for providing an extended set of HTML ‘native’ components. Let’s say your company has multiple frontend SPAs with different technologies (angular, react, svelte,…) they could all use the same set of company custom components, like a custom datepicker, or fancy selectbox.
epolanski
9 months ago
This is the promise, but my experience tells me that web components fall short of that goal.
epolanski
9 months ago
This has been a major concern for me.
We went for a web component because we needed the same functionality on different websites using different tools.
Issue was that we authored the web component with tailwind and then deployed the web component on different websites, some having different versions of tailwind themselves. Even minor differences in hosts tailwind versions led to quite surprising results.
What we did in the end is to write a tool that given the tailwind classes used in the webcomponent it would then rewrite the rules at the :root of the web component's own css.
Another reason for unhappiness came from lack of isolation regarding the units that derive from the host's base font which forced us to work in pixels directly.
All in all, while I understand some of the decisions that went into web components, I can't lie and say that I too have few reasons to not be fully on the web components train, they fall short of the promise of author once, use everywhere.
kccqzy
9 months ago
For the specific point about useState, I agree about it being too magical. These days when I do write frontend code I use Reagent in Clojurescript. (I use Clojurescript partly for other reasons like its elegant syntax that's better than JSX, and built-in immutable data structures.) Its implementation of (r/atom) is a whole lot more intuitive: you can even think of it as a mutable pointer where the dereferences are tracked. On the other hand useState just feels like a hack for people who really want to avoid writing both classes and closures, and it is a roundabout way of doing things that could have been done in a much more standard and familiar way.
blovescoffee
9 months ago
How does your library deal with state management and data flow? What primitives does your library offer for optimization?
wruza
9 months ago
How does a regular program deal with “state management” and “data flow”?
We all just programmed things for decades when web guys pop out with this “state management” pseudo-problem and started to invent thousands of pseudo-solutions for it.
And why do we need “optimization”? It’s a user interface, not an accounting software core. A user types a character, you update few divs content or way under a thousand of divs’ visibility. Which optimization does that need?
blovescoffee
9 months ago
First "Web guys" is such a demeaning way about talking about real and serious engineers solving real and serious engineering problems. If you don't think frontend engineering solves serious problems, I don't think your opinions about it are serious.
All real world programs are stateful. You need some tooling and/or conventions to handle that in a clean way. I recommend this blog post about React Query that talks about some challenges and solutions on the frontend for state management: https://ui.dev/why-react-query
You're questioning the importance of optimization on a website for hackers/tinkerers/engineers?
You need optimization for page speed, SEO, animation, elegance, pushing the boundaries...
edit to address: "Which optimization does that need?"
Optimistic updates, debouncing, handling large responses, cache, etc. etc.
wruza
9 months ago
Can you recommend a blog post about “state management” in non-frontend? E.g. some server or maybe a desktop app like e.g. your backup manager. Because my whole premise is that the “problem” is self-imposed, which react is literally the part of.
If you don't think frontend engineering solves serious problems, I don't think your opinions about it are serious.
I don’t think “frontend” is at all serious, because I have developed user-facing systems since around 2000, and “frontend” (which we called gui controls back in the day) was never a biggest story, when it was worth telling at all. Mostly complex distributed accounting software with various integrations at all levels. I’m not afraid of appeals to serious engineers with serious problems, cause I am one of them and can question it freely.
If I appear somewhat toxic, that simply reflects the toxic positivity about the absurd state of things in web dev. It is a collective delusion which suddenly disappears when people get forced out if it, by e.g. going htmx route. Not advocating for htmx specifically, it just happens to be a perfect litmus test. Same for php, people still use it outside of “frontend” bubble and don’t know that “managing” their “state” is a hard problem that requires tens of versions of the best framework of the month.
Izkata
9 months ago
> Can you recommend a blog post about “state management” in non-frontend? E.g. some server or maybe a desktop app like e.g. your backup manager. Because my whole premise is that the “problem” is self-imposed, which react is literally the part of.
It's largely unnecessary there because those can talk directly to the database and use it as their data store without a large performance penalty. Plenty of server-based systems like PHP don't even have persistent state to manage, whatever wasn't stored in the database is discarded when the response is sent.
> It is a collective delusion which suddenly disappears when people get forced out if it, by e.g. going htmx route.
There is a performance penalty here where every state change is a web request. That's a large part of where frontend state management libraries began, with Backbone providing objects that would be synced with database tables and acted like a local cache.
wruza
9 months ago
I was talking more about thick clients. Htmx and php were just examples where “it” disappears in webdev. So please don’t take them as good examples for this topic.
There is a performance penalty here where every state change is a web request. That's a large part of where frontend state management libraries began
That mode of operation is actually anti-frontend. Frontend (thick client) means that you have a local context with manual or eventual syncronization (aka [auto]save and [auto]update). Using these modern “state management” frameworks this way is double fault, cause you basically simulate 1.0 in 2.0 via now mostly useless approach that didn’t make much sense to begin with.
Request penalty is not a new thing. 20 years ago LAN servers had connection properties similar to the modern internet. Somehow (and I say this ironically, it’s very straightforward “how”) db servers, app servers, thin and thick clients and bare apps worked without “managing state” via some semi-functional but not really DSL language wrapping anominations. Only web, which was always a second class dev env invented the problem from its own poor childhood: jquery et al, no concept of permanent storage, poor io-unaware language until around 2015.
papichulo2023
9 months ago
Old way was storing data in sessions or hidden html inputs. Both way worse than modern alternatives. You kinda sound like you have no idea what you are talking about. Having to render thousands of elements is not uncommon.
qudat
9 months ago
JSX is the worst part of react so I find that to be a pretty wild take.
postalrat
9 months ago
You honestly can't think of anything worse than JSX? JSX bothers you more than all the ways useEffect gets used or the restrictions for hooks.
qudat
9 months ago
The use API is very simple; JSX is a bastardized version of html that is atrocious to read and write. Just imagine all the dev time spent dealing with jsx/tsx. From IDE support to babel, typescript, etc. it is a burden on the JS/Ts ecosystem and severely contributes to fatigue.
Yes. JSX is extremely complex to support and it is absolutely the worst part of react.
postalrat
9 months ago
So what is the alternative that solves all these perceived problems?
imtringued
9 months ago
Hyperscript was a mistake.
azangru
10 months ago
> In my view the only thing we should retain from the React era is JSX
How do you deal with the non-existing difference between attributes and properties in JSX? Is every attribute a property and vice versa? Do properties reflect back as attributes?
edwinjm
9 months ago
In Lit, a web component framework, you can set properties with, for example, href=... and you can set attributes with .href=...
This can be taken over to JSX.
azangru
9 months ago
> In Lit, a web component framework, you can set properties with, for example, href=... and you can set attributes with .href=...
Only it's the other way around.
nsonha
9 months ago
jsx is just a syntax to construct elements with attributes. You can still add properties like you do in a web component. In React you mostly never deal with instances (and properties) but that doesn't mean other ways to model components utilizing jsx cannot.
azangru
9 months ago
Jsx uses properties, not attributes, while pretending that it uses attributes. Html attributes are strings, whereas jsx allows you to pass different data types to child components. Thus, properties. Which is also why is uses camel-cased names, or insists on className. Because these are the names of HTMLElement's properties.
WorldMaker
9 months ago
Those are React optimizations/restrictions, not JSX restrictions. They want to make diff/patch as fast/simple as possible and rely on properties to do that as much as possible. `className` might have been a restriction in early JSX parsers trying to avoid keyword clashes, but every current JSX parser (especially Typescript) has no problems with JS keywords embedded in JSX. (I don't think it actually was a restriction at any point, but early JSX parsers might have been conservative in how they wanted to parse given the fate of E4X.)
Snabbdom [1] takes an approach of explicitly separating `props` and `attrs` at the expense of extra verbosity in the JSX `<span props={{ className: 'example' }} attrs={{ 'aria-label': 'Example'>Example</span>`. My Butterfloat [2] uses simple heuristics, starting with the props because you can conditionally type a ton of JS type data (and MDN link comments) out of TS DOM types for a strong autocomplete experience, adding common important-to-HTML copy/paste shortcuts such as `class` and `for` and switching to attributes if an XML namespace seems to be in use or the name includes a `-` and seems to be qebab-cased rather than camel-cased.
[1] https://github.com/snabbdom/snabbdom?tab=readme-ov-file#jsx
rschristian
9 months ago
Every JSX implementation uses a mix of setting props & attributes, depending on the specific label, as the DOM can be a bit weird with how some things reflect. Generally properties are preferable to attributes, however.
nsonha
9 months ago
that's React's implementation, we are talking what it would be if not React. IMO the semantic is similar to attribute, example:
let element = <my-thing my-attribute={value} />
element.property = prop
Narhem
9 months ago
If you use web components enough you realize why tools like useState exists then you have to bring in another library like alpine to offer the functionality.
The whole point of web components is the ability to offer class encapsulation within the browser without anything other than a file server.
JSX has much nicer syntax but I’d rather not have to deal with the overhead of launching a node server. Makes developing time quicker when working with smaller codebases.
sandreas
9 months ago
Well, there is a project to convert react components to native ones[1]... this way you can write react and use it everywhere. I think this is the way to go, similar to svelte's approach. Write what you want but compile it to native standards.
wslh
10 months ago
> I don't want to learn a complex framework.
Completely agree. As a casual programmer, I just want something simple, inspired in VB6.
jrochkind1
10 months ago
You implied but didn't say explicitly, are you doing your front-end development with web components now personally?
jeswin
9 months ago
Yes.
deliriumchn
9 months ago
> I don't want to learn a complex framework. I don't want to learn magic that I don't understand without reading the documentation (useState, createSignal et al)
I'm always suprised reading statements like that. No offence, but maybe you're in wrong career if you don't want to learn how most popular and important tools of today work... Not to mention that its so simple you can learn everything required to be efficient during lunch break
lelanthran
9 months ago
> I'm always suprised reading statements like that. No offence, but maybe you're in wrong career if you don't want to learn how most popular and important tools of today work... Not to mention that its so simple you can learn everything required to be efficient during lunch break
This is such a common comment that I am never surprised to see it pop up whenever the "front-end mess" discussion arises.
No, you cannot learn React over a lunch break. You cannot learn Angular and Vue over a lunch break.
I am skeptical that even you, personally, can learn just the footguns alone present in the hundreds of thousands of lines of code in a specific $FRAMEWORK over one lunch break, two lunch breaks or even a dozen lunch breaks.
All those thousands of lines of code implement something, and I will wager a month of my income against a month of your income that you will not learn more than 3 or 4 concepts over a single lunch break, because they all have multiple concepts, multiple use-cases, multiple exceptions-to-the-general-rule and multiple footguns without even including the edge-cases they solve.
You will spend several years of lunch breaks, unless you consider reading the wikipedia overview for each $FRAMEWORK to be "learning the $FRAMEWORK".
Web components, OTOH, have less functionality than full-blow $FRAMEWORKS, but each can be individually learned over a lunch break, reused by non-JS-developers and is a knowledge base that is more or less future-proof.
watwut
9 months ago
React is particularly easy to learn tho, much easier then angular.
What you definitely can not learn over lunch breakis whatever local developers created as a local ad-hoc framework. Those area always more time consuming to work with, because you have no internet, stack overflow or documentation to help you.
gspencley
9 months ago
> In my view the only thing we should retain from the React era is JSX (for many reasons, true type-safety, autocomplete etc)
Warning: opinion incoming.
JSX is one of two reasons that I never liked React at all and wish it would go away.
I've been developing "web applications" since the latter half of the 90s. I've worked with everything from an in-house built dynamic template language (very similar to what PHP did in the early days) developed in C++ and served using CGI in Apache, to developing with PHP to Java Spring MVC to Django to modern frontend frameworks including both React and Angular.
JSX reminds me of what PHP was like in the 90s and early 00s. People adopted it widely because the barrier to entry was extremely low. We had all of these static HTML websites and "developers" could just go in and start adding control flow to those documents in order to add dynamic functionality. It was easy ... and it quickly turned into a complete mess so big that PHP ended up with a reputation as being a toy language that "serious programmers" wouldn't be caught dead touching. That reputation was a bit unfair but also kind of earned.
With the rise of PHP's popularity, the PHP "community" itself came to realize that they had a decent turing-complete programming language that they were working with, but that this idea of mixing business logic within HTML documents was a massive anti-pattern. It's ironic that what began its journey as a template language eventually realized that the best thing for the language was to stop using it as a template language, and to adopt different template languages such as Smarty in order to promote a separation of concerns between view / presentation concerns and business logic.
React was never created as a "framework." There are actual frameworks that are starting to come out that use React for its view layer, such as NextJS, but React itself is just a library that allows you to create custom components and then choose your adventure when it comes to what other libraries you want to mix and match. But because people reach for React to start throwing together dynamic frontends quickly, everything is compononent-first. So it actively encourages you to put business and integration concerns in what really ought to be your view / presentation "layer."
And JSX magnifies that problem by just being JavaScript. So, again, it's PHP all over again. You've got a very powerful turing-complete programming language that you intersperse with your markup and you get messes. Even in the most well-written, concern-separated React projects I still see a lot of "ugliness" that comes through with JSX.
I did mention that it was one of two reasons I'm not a fan of React, the other is that - again because it was only conceived of as a component / view library - there is no inbuilt view encapsulation / scoped styles. This problem is somewhat mitigated by CSS modules these days. But view encapsulation is something that I've always seen as Angular's killer feature - the ability to just style your tags directly and create component markup that is completely devoid of class="" attributes. Angular and VueJS actually trained me to hate 99% of class="" attributes and to think of them as a type of code smell... just because it is possible to create higher-level components that don't have any at all but still styling when needed.
stickfigure
9 months ago
Separating components is more important than separating presentation and business logic, and React/JSX excels at that. Old style MVC and templating frameworks that promised clean presentation/business separation ended up with two giant muddled piles of disorganized code. Components gave us a better organizational structure for complicated UIs, and that's why that form of separation won out.
If you have nice clean modular components, it doesn't matter too much where the code vs template boundaries are inside. They shouldn't be so complex that it matters. This is why I like JSX - for any given component, everything is in one place.
gspencley
9 months ago
> and that's why that form of separation won out.
React won out because it has a low barrier to entry and is very unopinionated. That's not a bad thing. But don't pretend for a second that it won out as any kind of industry standard because it was technologically superior or was a better designed "framework" (again, it's not and never was a framework, it's a view library for creating components).
There are 3 broad concerns when it comes to programming for the virtual machine that we call the web browser:
- Semantic demarcation, which is what markup does: this is a paragraph, this is a header, this is card etc.
- Visual decoration and styling, what CSS does. This is how a paragraph looks, this is how a card looks etc.
- Interactivity and control flow: what JavaScript does. When the user clicks the button this is what happens.
Those are all distinct responsibilities which the browser handles separately natively.
We don't need to even start talking about MVC or OOP design patterns when talking about spearating your concerns. That's a basic engineering concept of isolating your moving parts to keep things simpler and allow you to change things in isolation without acccidentally breaking something else, which is the bane of software maintenance.
The notion that diluting separation of concerns is a design innovation that makes software development and maintenance somehow easier is truly baffling.
stickfigure
9 months ago
I think you missed my point entirely. The lesson of React and JSX is that separating semantic/visual/interactivity is not actually valuable when building web applications. The valuable separation is component separation. React/JSX nailed that. Previous web development frameworks/libraries were terrible at it (though angularjs gets an honorable mention).
I worked through this whole era when the web platform was figuring this out. Or I should say re-figuring this out, since desktop GUI development had worked it out going back to the late 80s.
imtringued
9 months ago
Some of us need to get work done and not worry about the XSS potential that inline styles represent so we set our CSP to block all inline JavaScript and CSS.
Btw I'm sorry if I misunderstood what you're trying to say, because you're mostly dissing the class attribute which I very much depend on purely to keep my websites secure.
gspencley
9 months ago
Yup you misunderstood. I would be just as much opposed to inline styles as using class="" attributes.
With frameworks like Angular, you can create a component and bind CSS styling to that component in a way that you can select just your HTML tags directly ... like style div {} instead of styling .my-card {} etc. And those styles are not "global", they are scoped to only those elements that are referenced in your component's markup.
There are two ways that this can be implemented and frameworks often let you choose which one you want to employ: Shadow DOM or emulation. With emulation, the classes and selectors get generated for you at compile time so if you inspect the DOM you'll see tons of class="" attributes that were auto-generated ... but the developer never had to write them or think about them.
The result is code that is so much nicer to read and work with.
dangsux
9 months ago
[dead]
jaredklewis
9 months ago
> I never had to guess what "useState" does behind the scenes.
It's weird to me that React hooks are always dragged out in these arguments as some kind of bogeyman. If you understand the idea of a virtual DOM and a render loop, then it is only a tiny step from there to understand hooks. And you can understand all of these concepts in about 15 minutes: https://www.youtube.com/watch?v=1VVfMVQabx0
I just don't get all the hand wringing regarding frontend frameworks. I've been using React since 2014 and in 10 years, there has been exactly one big change to the framework: hooks. When they came out, I spent 15 minutes to understand them. It didn't kill me.
And React has been undisputed king the frontend frameworks hill for at least 9 years, but people still act like it's some sort of ever-changing, confusing landscape of options. If you want boring, stable front-end development, choose a super popular, well documented tool like React. Or if you don't like frameworks, use vanilla JS. It's not a crisis.
ForHackernews
9 months ago
> If you understand the idea of a virtual DOM and a render loop, then it is only a tiny step from there to understand hooks
Once you understand the arcana of the magisterium, it becomes obvious why the encyclicals must be unitarian!
edwinjm
9 months ago
"This framework feels very natural to me" says person using the framework for ten years.
watwut
9 months ago
I came back to react around a year ago, hooks were completely new to me and pretty instantly understandable. They are just not difficult to comprehend or use.