> Vue uses a templating language closer to default HTML than to JSX, which makes it much easier to write conditionals and loops in template files, without having to reach for workarounds like map and ternaries
I like react/jsx precisely because I can use language constructs like filter, map, reduce, etc, instead of a custom implementation of basic things like if statements and loops. I find this much more ergonomic and didn’t realise some people see this as a “workaround”.
Worth also pointing out that when you write these templates, as strings or template literals, they might resemble HTML in appearance but really have no relation to actual HTML except what they output after processing. All of the added directives also have no equivalence in HTML. You’re just writing JS indirectly.
This. Most of the value-proposition of JSX is that it is just JavaScript and as such you just write code logic like you would normally do. Need to filter some items? You can do that with the Array.prototype.filter method you already know. Do you need to return a list of components based on some list of object values? Just use Array.prototype.map.
I never really understood those that see this as a weakness and would rather learn a more limited set of template string functions that work kind of like, but not entirely like, the native JavaScript collection functions.
Yes, using a ternary operator in JSX to conditionally render components/values looks a bit ugly, but nothing is stopping you from making a wrapper component like:
Also with JSX/TSX scopes behave exactly like they do in regular JavaScript, because it is regular JavaScript. Templating languages often invent their own form of scoping mechanism.
> nothing is stopping you from making a wrapper component like...
I'd suggest avoiding that, since the inner JX expression will be evaluated even if cond is false. In the best case this just means some unnecessary allocations, but in other cases it can cause unexpected errors (e.g. you check obj != null then try to use it inside the if).
> Yes, using a ternary operator in JSX to conditionally render components/values looks a bit ugly, but nothing is stopping you from making a wrapper component like:
Couldn't you put that in a function that returns the correct JSX element or am I misunderstanding the problem? Something like:
Plus, the power of being able to treat JSX as any other JS object means that you can use standard JS constructs like loops - slightly contrived example:
const items = [];
let runningTotal = 0;
for (const item of someArray) {
runningTotal += item;
items.push(<li>Item {item}; running total {runningTotal}</li>);
}
return (<ul>{items}</ul>);
The closest example I can find in Vue would require a computed property to implement something like this.
Disagree. I would argue your example is hard to read compared to the equivalent in Vue, and it mixes business logic (computing the running total) with the rendering logic.
I don't think this is a good way to build JSX from lists.
Better to keep components smaller. Also this way will show React linting rules, like the "key" requirement.
It's technically possible, but it looks horrible and should be avoided because of lack of readability. Keep the templates plain and simple, and store your business logic elsewhere.
I liked JSX a lot when I was using React. However, writing business or view logic in templates is a maintainability nightmare. With JSX it's very tempting to do this and I did this often, but it's still a mistake and I regretted it every time I visited my spaghetti JSX months later.
When it comes to comparing React with Vue or Svelte, the templating is not the critical factor.
The JSX bits in a React codebase aren't templates, at least in the traditional sense where a template is a static file that looks like some desired runtime output and contains some "slots" which are analyzed at build time (or program start time) and then filled in with dynamic values at runtime. JSX kinda looks like that, but there is actually no "templatey" stuff happening at build time, i.e. React does absolutely no analysis whatsoever of your JSX and has no idea what it contains until each new time a component renders at runtime.
I totally agree. Templating is not the critical factor indeed. The templates shouldn't contain business logic so they should be simple by default. If not then you're following an anti-pattern.
The crazy part is that there's not a really good reason why we couldn't make if..else function as either a statement or expression depending on the context. I think there's a proposal to do that.
This discussion never ends. It's so subjective and totally not important at all. Templates shouldn't contain complex logic anyway, only formatting logic with some for loops. You can learn any syntax in 30 minutes if needed. The battle isn't fought on the hills of templating logic. It's sad because there are many interesting differences other than templating logic between frameworks, but they are less superficial so they get little attention.
Especially with copilot, which is clearly well trained on React and JS, I find I often just need to write the first few characters of an array method or other common method and it will generate 10 or so LOC that are at least 90% of what I want.
In defense of those directives and template languages, they compile down to efficient operations that every developer can take advantage from. I like that `v-for` is likely more efficient in regards to how it operates than how an average developer might write such a function, especially when dealing with nested data or more complex situations. Other efficiencies can be gained by using a template language as well via the compiler.
Not that you can't with JSX (Solid and Qwik use JSX and have transparent ways of doing optimizations as consumer of those frameworks) but its not currently the default, most (if not all) optimizations must be done "by hand", is a big tradeoff for some places.
This can be the case, but as I understand it typically isn't so, at least with most big frameworks. For example, I believe Vue templates are typically translated to a hyperscript-like render function that has a similar efficiency to the average React render function. Indeed if anything, I would imagine Vue would be slightly less performant, because the v-for loop is quite abstract and can handle things like looping through objects, so there must be a reasonable amount of machinery to handle all the different loop cases.
The state of the art is less about handling things like loops, and more about reducing the amount of work needed to render static elements. For example, say you have a single component that renders a static table, and in each cell of the table you need to render something dynamic. In the classic vdom system, you'd construct a `table` node, with a `tbody` child, which in turn has `tr` children, which was contain `td` nodes, and then finally in the `td` nodes you render the dynamic content. This works, but most of the content isn't actually changing, only the contents of the `td` nodes. What modern frameworks like Solid and Svelte do is to compile that whole nest of nodes into a single HTML string, and then add instructions that specify where exactly the dynamic content lives. That way, on the initial render, the browser is doing more work natively, and on later updates, only the new content needs to be checked and changed. I know there's a library for React that adds similar capabilities there, albeit with a few more constraints than in other frameworks.
I do know Solid does for-loops differently than in other frameworks, but this is less to do with efficiencies gained by compiling, and more about how to optimally use the signals system that it uses for reactivity. Apart from that, I don't really know of any optimisations that would make something like `v-for` any faster than `.map(...)`.
In general I really like React but after spending years tinkering with JS and seeing my codebases rot away faster than I could keep up due to ecosystem/tooling churn (I started in 2014 when React was ES5 and still using mixins), I started replacing my frontends with regular server-side rendered ones. I enrich these with vanilla JS and some smart things like using async fetch and the history API to seamlessly replace content when clicking links. There are of course solutions like HTMX or Turbolinks that do similar things but it's really easy to make something simple work with just JS.
With some of these tricks the resulting application feels very similar to a real SPA. Of course if you're really building an application in the sense that a lot of the computation and state handling happens in the browser you will still need to use JS, but even then I would just go with vanilla JS in most cases. That said my experience is from building mostly CRUD-like apps alone or in small teams, so I can see the benefit of more complex toolchains in larger organizations.
But yeah, browsers and JS offer so much out of the box, most people don't seem to realize how easy it is to do cool things without relying on frameworks.
Ok so this is topical for me right now. I somehow managed to avoid the world of react since it became a thing. All the code i was writing was pre react and we kept the old frameworks, and that’s was all good and well.
Fast forward to today, i took over a project that is full react. What a mental shift. Having said that, sometimes i love it, sometimes i hate it. A friend put it best when he said “i struggle to predict what might be trivial and what will take a full day or two”, and that’s my experience too.
I found myself just the other day wishing i could await the setting of a state variable, it was making saving a file in a complicated form a little difficult. I found a work around but i don’t love it and i know the next time i come back to work on it I’ll be scratching my head at what i was trying to achieve and why i did it this way. Naturally i over commented my rational here.
I do miss writing in basic js and server side code, it’s probably slower over all, but i do miss it for the simple things being predictably simply and the hard things typically being predictably hard.
You don't need any of it. You can write vanilla JS, using ES6 classes, as web components and be done with the whole front-end framework game. All you need for data-binding is an Observable of some kind that can loop through listeners for events and call their handler. Component classes all have a render function so that React kids feel at home. Those components are registered using CustomElementRegistry.define [1]. Tools like vite help roll up all that code and styles into a minified bundle but doesn't include all the crap that these "modern" frameworks add. Take this from someone who has been writing web sites since 1996. You don't need any of those frameworks unless you're looking to give away control of your product to the roadmap of the framework or need to hire a bunch of people to accomplish something quickly and all they know is React.
Not sure if this is what you settled on, but I'd just initialize the state variable as null and then put it into the dependencies of a useEffect that fires when the variable is set
I realize this is unsolicited advice, however this sounds like you're hitting the "DOM has an imperative API but React is declarative" barrier, because React (until `use` ships at least) has no way to just await reactive values, you can:
if sufficiently complex, you may want to look into `useSyncExternalStore`[0] which can be used to store and update state (IE maintaining UI reactivity) in a microcosm.
Otherwise, I'd recommend framing it as a series of dispatch-able steps, which maps well to `useReducer`[1] possibly in combination with `useEffect`
> I found myself just the other day wishing i could await the setting of a state variable, it was making saving a file in a complicated form a little difficult.
It used to be that React.setState would accept a callback function to fire after the state was set.
The newer setter function returned by useState doesn't have that anymore I'm pretty sure. Tbh I've never tried though.
if you need to await a setState call, you're prob structuring your logic in a less-than-efficient way. in whatever handler is calling setState, you should compute the next state in the handler, setState(nextState), then use that nextState for whatever comes next.
Yeah, for my personal apps I just write offline-first apps. I need to make it so I can build apps as efficient as I can as I don't have a lot of free time. So, I wrote a little library under 1kB that just finds where I left off and re-centers/focuses there. It makes for dead simple applications.[^1]
I also created an HTMX-like library that is focused on forms so it stays to the HTML speck pretty closely. I need to make a couple of corrections to it. But it is amazing how far it can get you and much smaller footprint than HTMX. Granted, it can only do a fraction of what HTMX can do.[^2]
This sentiment makes sense up to the point where you are being glared at by a sweaty PM that can't understand why your foo widget can't be moved to the other side while blinking and ajaxing because HTMX doesn't work like that
I’m using this approach for a side project and it works great. Just traditional express, tagged template literals (with some xss escaping helpers) and stimulus + turbo. Using vite for bundling and reloading on changes.
Having spend over a decade in Python backend/JS frontend ecosystems at this point, I can confidently say from my experience that Django backends are much easier to update than React frontends. If you import every bleeding-edge nonsense through pip that you can, there can still be problems, but Python has a better culture around this, so it's usually easy to steer teams away from doing this. In JS, importing every bleeding-edge nonsense through npm that you can is the only culture I've found, and this problem is pervasive enough that even guarding your direct dependencies doesn't isolate you from it, since your dependencies are likely to introduce bad dependencies of their own.
Of course any system will require maintenance. The question is more about the significance and frequency of the maintenance required.
You can take a Ruby on Rails app from 2005, and it will mostly look the same as a 2023 Rails app. You'll need to update some gems, use the newer routing DSL, and update the environment configs. But that's pretty much it, after nearly 2 decades.
Contrast that to a React app written 5 years ago, where you'd pretty much need to completely rewrite everything (class components => functional, use hooks instead of callback methods, etc.)
I've just updated a codebase from Django 3 to 4, about to do another one. It took very little time, with 0 breaking code changes and a mandatory postgres update to 12+.
Even going from pandas 1->2 and celery major version bump (5, I think) caused 0 problems. Mature codebases like these tend to be careful about backwards compatibility.
As someone with over a decade of Django experience, _very little_ has changed in Django since it started; you can bring up a very old app to speed in a matter of a couple of days.
I've had to spend a week moving a 3 year-old React app to the latest versions and failed because certain dependencies were just a mess.
Web Components have got to be the single most overrated web feature I've ever witnessed in the many years I've been messing around with browsers. You know, even WITH React and no Web Components, there was already a pretty reliable way to integrate third party libraries into React without a ton of glue: the DOM. Like for example, if you want to integrate a text editor like Monaco or Quill, basically all you have to do is give it a DOM node and tie together whatever props/events/bindings you want. You don't really need monaco-react, which is not even a large library to begin with.
The main reason why React is still popular is, drum roll please... The programming model. JSX is not an antiquated idea, it is still one of the better ways to integrate the UI part of a JS application into the JS part directly. I greatly prefer JS logic inside of my HTML versus a bespoke template language specifically because it's easy to compose and construct complex logic in.
I've been messing around with Svelte a bit in spare time. I really like Svelte and will probably continue to use it, but the two things I will note is:
- The integration with Web Components is imperfect and doesn't really hit me as something I would seek out.
- The templating logic in the HTML feels decidedly inferior versus just being able to use JS logic and JSX. Try doing a for loop where you count up; the best answer I could find on the internet was to construct an Array using `Array(number)` and enumerate over it...
What I really want is actually more like React's programming model with Svelte's "compiling down to nothing" mantra.
But this Web Components fervor, I know people get very heated about it, but I strongly believe that in 10 years it's going to be one of those grotesquely complex legacy features nobody can get rid of.
That looks great. It doesn't mention compiling down to nothing, but it definitely offers the programming model of React Hooks without needing a virtual DOM, which is already a good innovation, and probably something I'd like more than Svelte.
Once upon a time, I remember one of the plans for React was the ability to compile components into web components. Your code wouldn't have to change at all, but it would mean CSS couldn't leak in/out of the component boundaries like it does now. I think it would've also made it easier to use a React component in other frameworks, since all they'd see is the common web component interface instead of the React interface?
> I remember one of the plans for React was the ability to compile components into web components.
This was also the case (-ish) for Vue, Svelte, Solid. Their authors were really bullish on web components in the beginning. Now they are all on the scale from extremely negative towards them to completely indifferent.
While JSX is very well suited for programmatically defining your UI, it's about all that React is worth these days. You know about string literals right? You don't need JSX and in-fact can get away with:
My perspective is that JSX is all that React has to offer. And lots of developers - myself included - were doing "JSX" a decade before React arrived. Because it, like, super obviously a good idea.
you know about injection vulnerabilities, right? if you really want to spaghetti code your app with string representations of html, you can also use `dangerouslySetInnerHTML` in React.
Hmmmm. Does that do escaping and such, or are you boned when an angle bracket shows up? Plus if the nodes are already parsed in your code it kinda sucks to stringify them so the browser can re-parse them.
Not to mention holding focus and other element state, would that just get blown away and replaced with a whole new element every time? (Where react does tree reconciliation to avoid unnecessarily blowing away and replacing elements)
Maybe you’re only addressing the point about programming model, but this approach seems like it has some issues.
The shadow DOM is a great alternative to using iframes to get style isolation from the larger app, but everything else about custom elements/"web components" has better alternatives in user-land.
That's not really a huge improvement over just making a sparse array though, is it? Looks more confusing to me. Could be wrong but I'm pretty sure e.g. Array(1000000000) does not actually allocate much.
captain obvious here, Polymer became LitElement which became the invisible Lit.dev (branding direction on par with twitter becoming x); pretty much state of the art on top of web components; not that anyone noticed, as I said--meetup.com keeps prompting me to take over one of the web component meetups where the (or one of) lead of the project can't seem to muster the effort. a bit frustrating when the lack of awareness is so profound and extensive--as evidenced by many of these comments, over many years. I'm sure many more projects will make the mistake of choosing React and Svelte before the conclusion mentioned here bubbles up.
I think JSX was a mistake and just using hyperscript would have been better for the ecosystem. I think frameworks peaked with mithril and have been downhill ever since.
Those other tools you're using almost always give you a set of callbacks or events they will fire.
Just use the normal event handlers. If you're tied into a store (ex: redux/zustand/recoil/context/etc) just update the store from the non-react library and things will work themselves out just fine.
You can watch the DOM with mutationObservers, but if you own both pieces (react and non-react) why would you bother? They can both coordinate just fine.
MutationObservers really shine when you happen to missing an eventHandler you want in a library, or you're running on someone else's DOM so you don't control both sides (ex: you're an extension content_script).
I think the people expressing negativity about hooks are a small minority.
Hooks are a massive step up from class component lifetime methods, and the composability of hooks can lead to some very clean and powerful code if you know what you're doing. We're using hooks at work, with rules-of-hooks linting, and I can't remember the last time we had an issue or bug because of hook semantics
I think they're a bit of a mixed blessing. The way they can decouple business logic from view logic is absolutely fantastic. But having to wrap everything in useCallback and useMemo to avoid re-renders is a bit of a footgun and a step backwards from class components.
Like others I disagree that you have to wrap _everything_ in useCallback/useMemo.
However saying you only need those for performance reasons is wrong.
There are cases where avoiding re-rendering (thanks to useCallback) is avoiding an infinite loop.
I created a codesandbox[1] to illustrate this. Wrapping the "reset" function in a useCallback solves the infinite loop.
If your initial reaction is: "you should not create logic like this" or "you're adding unnecessary stuff" please note that this is a stripped down version of a real use case, where things make more sense.
The point is that it's hard to come up with a rule as to when to use useCallback. The best I can think about is: "if you don't have direct vision on where your function will be consumed, wrap it in useCallback". For example, when your function is defined and returned in a hook or defined in a parent component and given to children.
The point is that any of those children/consumers could have this function in a useEffect and so list it as a dependency of this useEffect.
> The way they can decouple business logic from view logic is absolutely fantastic.
It’s a great idea to decouple business logic from view logic, but then hooks are the wrong place to start. Last time I checked, you couldn’t use them at all outside of a React component. That’s just a terrible place to put your business logic if you want it to be isolated from the specifics of your view.
I’ve mostly moved away from React, so maybe this has changed recently, but it seems difficult considering the fundamentals of their design.
Best practice in general is not to use either of those hooks unless you notice performance issues, or have a good reason to, React is optimized pretty well and unless there are serious numbers of rerenders happening they aren't noticeable.
Hooks are a step in the right direction, I just have a feeling that having to wrap in useCallback and useMemo and having to add dependencies manually can't be the final step of web app development. I look into the author's suggestions for the next generation of hook api in other libraries. However, I still don't want to rely on those libraries in large long living projects.
My understanding is you don’t usually need useMemo and useCallback, unless you’re seeing performance issues and your profiler is pointing at un-memoized
code as the culprit.
I sometimes check React discussions and it's full of new made-up terms about managing issues that are uniquely caused by React or some previous iteration of a React technique. What happened with the simplicity of just "generate some boring ass HTML DOM in JSX, and it applies the diff to the actual DOM". That's it. That's the entire value proposition of React and it needs no hooks, handles, states, immutables, events, data trees, properties, arguments, components, nothing else. Oddly that still works just fine, but no one uses React this way anymore.
> I sometimes check React discussions and it's full of new made-up terms about managing issues that are uniquely caused by React or some previous iteration of a React technique.
In other words, you're checking React discussions and finding discussions on how to maintain React code. What were you expecting to find?
> What happened with the simplicity of just "generate some boring ass HTML DOM in JSX, and it applies the diff to the actual DOM".
React happened, which does just that but transparently and effortlessly. In fact, React does it so well that a concern is to prevent it from applying those diffs when being updated when it doesn't need to.
> That's it. That's the entire value proposition of React and it needs no hooks, handles, states, immutables, events, data trees, properties, arguments, components, nothing else.
React does not need those features if you are using React for things other than developing graphical user interfaces, which by their very nature are stateful, emit and react to events, handle properties, etc.
React went from class components to function components and from lifetime callbacks to hooks. These concepts are completely orthogonal.
There exist design choices that would end up with a different combo. Class components with hooks or function components using lifetime callbacks.
Yes, hooks — basically sub components with possible effects and yielding values, or DOM output — are a terrific idea and much more functional and principled than explicit lifetime callbacks.
All the dependency arrays and non-conditional checks etc are because of the function components approach and don’t have much to do with hooks.
I feel nearly every discussion on hooks mixes this up and makes the whole conversation just weird and confusing.
I'm not a hardcore React user; I'm currently working with React, but I came here through jQuery, Angular 1, web components, and Vue. I've done two React projects: one really tiny one as an assessment where JSX was an eye-opener; components were classes, and React was simple and fun back then.
Now I'm working on a gigantic React project, and I'm surprised it's still working. It's all based on function components with all the hooks, higher order components, middleware components, and tons of other stuff. It works, and it's clearly maintainable, but it's not pretty. Endless useEffects after each other make it hard to see what's going on. Every change requires changes in half a dozen files at least; DRY is clearly not a concern here.
I'm not a React expert, but I think function components and hooks were a mistake.
One thing that strikes me is that years ago everybody was excited about ES5 finally adding classes, and now everything seems to be moving away from classes.
I think JSX is still a cool idea and an interesting alternative to templating, but I also think that if I were to pick a frontend framework now, I'd go with Svelte.
If you have lots of useEffects and the code is confusing, that just means you're not writing your code well. I've architected and shipped multiple react projects that generate min 100M + USD in revenue, so I'd say I'm well versed in production react. It is weird, sure. All web technologies are kind of weird. But it works great for large web applications.
Keep your functions small. Re-use is key - whether its hooks or components. Keep state sane by writing small functions that handle a couple state items internally, or create a parent state using context around a group of components.
React gets a lot of hate, but most of it is unfounded. It is just a tool. I see people write 800+ loc react components and wonder why it is "so confusing". The problem is obvious. The goal of using any technology is to make money, nobody cares (end of the day, just being real lol) about any of these esoteric practices that happen under the hood with effects, etc. Write good code and most problems disappear.
Unless you're working at Meta on react, or you have some burning desire to build tools like this (and honestly only <5% of devs who contribute will contribute something meaningful), there's no reason to pick so many fights with these tools.
Just use it by accepting its features and limitations, and craft your UI project well enough that it is maintainable and keeps printing money. Anything beyond that is a waste of time/effort.
If the same problem pops up a lot when using a framework, then at some point the framework is to blame. Yelling at developers "you are doing it wrong!" is meaningless, frameworks should naturally lead people towards the correct behaviors.
I find Angular much easier to reason about than the current state of React/Next. Which is funny because the biggest criticism of Angular years ago was its learning curve. Yet React seems to have become even more convoluted.
React and angular both had much bigger learning curves than vue. But between google and Facebook, I don’t think vie stood a chance popularity wise, even though I think it was the better of the frameworks at the time.
One reason you don’t want a class for every component is that standard JS minifiers won’t compress method call names, but can compress imported function names. So the cost in the minified bundle between a class component and an equivalent function component is huge, multiplied out by the complexity of the component.
`this.handleClick` vs `c`.
I still use classes for building data structured but don’t think creating classes should be encouraged by a framework.
> One thing that strikes me is that years ago everybody was excited about ES5 finally adding classes, and now everything seems to be moving away from classes.
For me the key advantage is much less boilerplate, readability and portability. The problem with `Stateless` components up until the introduction of hooks is that if you wanted state you had to write your component as a class so you ended up with components written in two totally different syntaxes with one being much more heavy on boilerplate.
The last key advantage i see is it brought the "React Components" way of sharing to logic. Previously every piece of logic you shared had to be connected to a react component, so you ended up with many "Providers" that were just a div with logic. Now with Context and Hooks you can easily transport that logic without the use of a Provider (well you still need one with Context but that a slightly different story).
The article starts by a quote of Alex Russel, paid by Google to specify Web Components between 2008 and 2021 - a technology in direct competition with React at the time. He is not a technologist to track or quote to get unbiased framework opinions.
I don't agree with most of the argument here, to the point where I think we live in totally foreign echo chambers that rarely exchange ideas. I didn't get any new idea out of this article, it didn't inspire me to do something I already tried 10 times in the past.
The website loads fast, and that's great. 10% of the CSS is unused. and that's a small blog. In the non-themed CSS, it's close to 50% unused. You could consider it a non problem - at scale dead CSS is complicated to manage, at least for me.
> paid by Google to specify Web Components between 2008 and 2021 - a technology in direct competition with React at the time
I’m personally of the belief that we should assess arguments, not employer. Someone working on a competitor to React can make very valid arguments against it, they’re often some of the most knowledgeable people about the drawbacks of the framework.
I’m personally not a fan of Alex’s abrasive style but I’ve seen plenty of his critiques of sites written in React-based stacks and they’re usually evidenced with bundle analysis, burn down charts and so on. They’re not unfounded.
(I also disagree that Web Components are a competitor to React. Frameworks like Preact and Svelte are interoperable with Web Components and build on top of the API. React chooses not to but that’s neither here nor there)
> (I also disagree that Web Components are a competitor to React. Frameworks like Preact and Svelte are interoperable with Web Components and build on top of the API. React chooses not to but that’s neither here nor there)
Used to work on Web Components (the browser side.)
Although we didn't take it as a competitor, in hindsight it was - at least in a sense. Both are component-based technologies, and the expressiveness of React and ES6+ made WC less relevant. I think WC is still nice to have, but it is no longer a must-have as it was originally envisioned.
The JS ecosystem has largely solved the problem by themselves without browser vendor's help (besides improvements of JS itself.)
I don't feel it's fair to brand "web components" as a technology that was in direct competition with React. I think the nuance matters.
They may have been solving similar problems then, and they may be optimized for different things now. But Web components are a web standard, and React is not. Pushing for web standard technologies is inherently unbiased because that's just betting on the platform. This results in pushing for platform improvements (like declarative shadow dom so it plays well with SSR, etc), and then everyone benefits.
IMO it'd only be a bias take if web components were branded as having no issues whatsoever, or that they are the most optimal solution for everything. I think it's okay to say, "web components currently don't solve my problems and that's why I'm looking to use something else like React or Solid". However, I've not seen this sentiment shared when it's the other way around with React. It's always "no one got fired for picking React" instead of actually evaluating what will deliver the most value to your users.
> Pushing for web standard technologies is inherently unbiased because that's just betting on the platform.
There's a ton of politics around web standards, and you can bet if Google manages to push through Web Environment Integrity, I will not consider people suggesting to use it "unbiased because it's a standard"
> I don't feel it's fair to brand "web components" as a technology that was in direct competition with React. I think the nuance matters.
Nuance doesn't matter to most proponents of web components. When they were introduced, for the first few years they were explicitly marketed as platform-native solution that makes frameworks obsolete.
Now the rhetoric seems more nuanced, but it's the same. It's only been upgraded to "build with lit".
> IMO it'd only be a bias take if web components were branded as having no issues whatsoever, or that they are the most optimal solution for everything
Mostly they are billed like that. And any voices criticizing them are either ignored or blocked.
I'd take that point further and state that React is in no competition with anything.
React was invented because Facebook had very interactive/stateful UI as well as large teams of developers working on the same codebase. The then conventional jQuery soup approach didn't cut it.
Should the web platform come up with a standards-based approach to solve the same problem, then this is not "competition", it is a blessing. It's not like React earns Facebook any revenue. Ideally, it wouldn't be needed or exist at all.
React has more implementation of its components model (preact, react, solidjs, inferno,…) than web components (chrome, ff partially and safari partially), is more used and is more indépendant from the current web monopoly. Anything w3c is now a standard to keep dominance.
Interesting article. I’m going to play devil’s advocate and come at it from a business perspective. There are huge advantages to sticking with an industry standard. It makes it much easier to hire devs. If you’re a dev it makes it much easier to get work. Having a big ecosystem means less building from scratch. There are huge network effects at play. In order to get serious traction in a market with network effects, the alternative doesn’t need to be a bit better, it needs to be 10x better. React displaced jQuery because it was 10x better. None of these alternatives strike me as being 10x better at this point. Sure they’re a bit easier for devs and a bit faster, but I’ve never had a customer complain that the app took 500ms to load instead of 250ms. There’s other things they care about a lot more. At some point another framework is going to displace React, but I think React still has a huge advantage at this point.
I still remember the day when angularjs was a new thing(around 2015 perhaps) and as a newcomer I was sucked into it. Just loved the thing. A year later, there were news about Observable JavaScript objects. So objects could send a notification about themselves having been changed. And when do so, do DOM changes could be done accordingly, without having to implement a render algorithm and having to compare shadow nodes with new render results to see what changed every time any data change occurs.
I don't think we are past that with React, and as the author mentioned there should be absolutely no reason for a developer to worry about rendering performance (the amount you have to use react, with for example useMemo, useCallback) and is something to be looked after and questioned.
Another argument of mine[0] would be the definitions that have been introduced by react. Component, state, hooks. It seems like we have forgotten about what they are actually called, and its function is in the context of programming (functions, variables, events, etc.). And so people become solely a React developer and can't really see a way out. (from the article: "And maybe—just maybe— your current satisfaction comes, at least a little bit, from simply not knowing what you’re missing.")
> there should be absolutely no reason for a developer to worry about rendering performance
i have a csv with one million rows. should i load the entire thing into memory and render 1m * column_count dom elements?
> Another argument of mine[0] would be the definitions that have been introduced by react. Component, state, hooks. It seems like we have forgotten about what they are actually called, and its function is in the context of programming (functions, variables, events, etc.).
a Component is a Component because it represents a node in the React tree. not all functions are Components.
state is state because it's more than a variable - updating it triggers re-rendering. a normal JS variable does not come with this reactivity.
hooks are not events. they are wrappers for reusable logic.
I like react/jsx precisely because I can use language constructs like filter, map, reduce, etc, instead of a custom implementation of basic things like if statements and loops. I find this much more ergonomic and didn’t realise some people see this as a “workaround”.
Worth also pointing out that when you write these templates, as strings or template literals, they might resemble HTML in appearance but really have no relation to actual HTML except what they output after processing. All of the added directives also have no equivalence in HTML. You’re just writing JS indirectly.
I never really understood those that see this as a weakness and would rather learn a more limited set of template string functions that work kind of like, but not entirely like, the native JavaScript collection functions.
Yes, using a ternary operator in JSX to conditionally render components/values looks a bit ugly, but nothing is stopping you from making a wrapper component like:
<If cond={...}><div>Conditional content</div></If>.
Also with JSX/TSX scopes behave exactly like they do in regular JavaScript, because it is regular JavaScript. Templating languages often invent their own form of scoping mechanism.
I'd suggest avoiding that, since the inner JX expression will be evaluated even if cond is false. In the best case this just means some unnecessary allocations, but in other cases it can cause unexpected errors (e.g. you check obj != null then try to use it inside the if).
Couldn't you put that in a function that returns the correct JSX element or am I misunderstanding the problem? Something like:
Simple ternaries are fine IMO but thats what I do when the logic gets complicated. I never used a nested ternary in that situation, for example.When it comes to comparing React with Vue or Svelte, the templating is not the critical factor.
Ternaries, booleans that cast to JSX, switch statements wrapped in IIFs...
I've done a lot of Vue and your bit of React and overall I prefer the Vue way here.
https://vuejs.org/guide/extras/render-function.html
> Vue uses a templating language closer to default HTML than to JSX, which makes it much easier to write conditionals and loops in template files
Not that you can't with JSX (Solid and Qwik use JSX and have transparent ways of doing optimizations as consumer of those frameworks) but its not currently the default, most (if not all) optimizations must be done "by hand", is a big tradeoff for some places.
The state of the art is less about handling things like loops, and more about reducing the amount of work needed to render static elements. For example, say you have a single component that renders a static table, and in each cell of the table you need to render something dynamic. In the classic vdom system, you'd construct a `table` node, with a `tbody` child, which in turn has `tr` children, which was contain `td` nodes, and then finally in the `td` nodes you render the dynamic content. This works, but most of the content isn't actually changing, only the contents of the `td` nodes. What modern frameworks like Solid and Svelte do is to compile that whole nest of nodes into a single HTML string, and then add instructions that specify where exactly the dynamic content lives. That way, on the initial render, the browser is doing more work natively, and on later updates, only the new content needs to be checked and changed. I know there's a library for React that adds similar capabilities there, albeit with a few more constraints than in other frameworks.
I do know Solid does for-loops differently than in other frameworks, but this is less to do with efficiencies gained by compiling, and more about how to optimally use the signals system that it uses for reactivity. Apart from that, I don't really know of any optimisations that would make something like `v-for` any faster than `.map(...)`.
With some of these tricks the resulting application feels very similar to a real SPA. Of course if you're really building an application in the sense that a lot of the computation and state handling happens in the browser you will still need to use JS, but even then I would just go with vanilla JS in most cases. That said my experience is from building mostly CRUD-like apps alone or in small teams, so I can see the benefit of more complex toolchains in larger organizations.
But yeah, browsers and JS offer so much out of the box, most people don't seem to realize how easy it is to do cool things without relying on frameworks.
Fast forward to today, i took over a project that is full react. What a mental shift. Having said that, sometimes i love it, sometimes i hate it. A friend put it best when he said “i struggle to predict what might be trivial and what will take a full day or two”, and that’s my experience too.
I found myself just the other day wishing i could await the setting of a state variable, it was making saving a file in a complicated form a little difficult. I found a work around but i don’t love it and i know the next time i come back to work on it I’ll be scratching my head at what i was trying to achieve and why i did it this way. Naturally i over commented my rational here.
I do miss writing in basic js and server side code, it’s probably slower over all, but i do miss it for the simple things being predictably simply and the hard things typically being predictably hard.
[1] https://developer.mozilla.org/en-US/docs/Web/API/CustomEleme...
if sufficiently complex, you may want to look into `useSyncExternalStore`[0] which can be used to store and update state (IE maintaining UI reactivity) in a microcosm.
Otherwise, I'd recommend framing it as a series of dispatch-able steps, which maps well to `useReducer`[1] possibly in combination with `useEffect`
[0]: https://react.dev/reference/react/useSyncExternalStore
[1]: https://react.dev/reference/react/useReducer
It used to be that React.setState would accept a callback function to fire after the state was set.
The newer setter function returned by useState doesn't have that anymore I'm pretty sure. Tbh I've never tried though.
I also created an HTMX-like library that is focused on forms so it stays to the HTML speck pretty closely. I need to make a couple of corrections to it. But it is amazing how far it can get you and much smaller footprint than HTMX. Granted, it can only do a fraction of what HTMX can do.[^2]
For anything stateful I just use web components.
[^1]: https://github.com/jon49/mpa-enhancer
[^2]: https://github.com/jon49/htmf
What about things like real-time (pushed preferably) updates based upon db changes, or another API finally sending streaming results, etc
[1] https://htmx.org/extensions/web-sockets/
[2] https://turbo.hotwired.dev/handbook/streams
- Ruby - if your Ruby/Rails app falls behind, you will be paying back debt to get it up to date
- PHP - if your Laravel/CI/Cake/Slim/Symphony App falls behind, you will be paying back debt to get it up to date
- Go - if your Go app falls behind, you will be paying back dept to get it up to date
- Python - if your Django app falls behind, you will be paying back debt to get it up to date
- Elixir - if your Phoenix app falls behind, you will be paying back debt to get it up to date
Counterexamples / Retorts:
- https://catonmat.net/5-best-programming-languages
- https://stevelosh.com/blog/2018/08/a-road-to-common-lisp/
Choose ecosystems free of hamster wheels, friend.
You can take a Ruby on Rails app from 2005, and it will mostly look the same as a 2023 Rails app. You'll need to update some gems, use the newer routing DSL, and update the environment configs. But that's pretty much it, after nearly 2 decades.
Contrast that to a React app written 5 years ago, where you'd pretty much need to completely rewrite everything (class components => functional, use hooks instead of callback methods, etc.)
Even going from pandas 1->2 and celery major version bump (5, I think) caused 0 problems. Mature codebases like these tend to be careful about backwards compatibility.
I've had to spend a week moving a 3 year-old React app to the latest versions and failed because certain dependencies were just a mess.
Go is backwards compatible.
The main reason why React is still popular is, drum roll please... The programming model. JSX is not an antiquated idea, it is still one of the better ways to integrate the UI part of a JS application into the JS part directly. I greatly prefer JS logic inside of my HTML versus a bespoke template language specifically because it's easy to compose and construct complex logic in.
I've been messing around with Svelte a bit in spare time. I really like Svelte and will probably continue to use it, but the two things I will note is:
- The integration with Web Components is imperfect and doesn't really hit me as something I would seek out.
- The templating logic in the HTML feels decidedly inferior versus just being able to use JS logic and JSX. Try doing a for loop where you count up; the best answer I could find on the internet was to construct an Array using `Array(number)` and enumerate over it...
What I really want is actually more like React's programming model with Svelte's "compiling down to nothing" mantra.
But this Web Components fervor, I know people get very heated about it, but I strongly believe that in 10 years it's going to be one of those grotesquely complex legacy features nobody can get rid of.
This was also the case (-ish) for Vue, Svelte, Solid. Their authors were really bullish on web components in the beginning. Now they are all on the scale from extremely negative towards them to completely indifferent.
But please, build something proper with just that and presumably a .innerHTML = ...
Let us know how it goes :)
Not to mention holding focus and other element state, would that just get blown away and replaced with a whole new element every time? (Where react does tree reconciliation to avoid unnecessarily blowing away and replacing elements)
Maybe you’re only addressing the point about programming model, but this approach seems like it has some issues.
Deleted Comment
Just use the normal event handlers. If you're tied into a store (ex: redux/zustand/recoil/context/etc) just update the store from the non-react library and things will work themselves out just fine.
You can watch the DOM with mutationObservers, but if you own both pieces (react and non-react) why would you bother? They can both coordinate just fine.
MutationObservers really shine when you happen to missing an eventHandler you want in a library, or you're running on someone else's DOM so you don't control both sides (ex: you're an extension content_script).
Solid JS!
However saying you only need those for performance reasons is wrong.
There are cases where avoiding re-rendering (thanks to useCallback) is avoiding an infinite loop.
I created a codesandbox[1] to illustrate this. Wrapping the "reset" function in a useCallback solves the infinite loop.
If your initial reaction is: "you should not create logic like this" or "you're adding unnecessary stuff" please note that this is a stripped down version of a real use case, where things make more sense.
The point is that it's hard to come up with a rule as to when to use useCallback. The best I can think about is: "if you don't have direct vision on where your function will be consumed, wrap it in useCallback". For example, when your function is defined and returned in a hook or defined in a parent component and given to children.
The point is that any of those children/consumers could have this function in a useEffect and so list it as a dependency of this useEffect.
[1]: Warning, clicking "Start" creates an infinite loop in your browser. https://codesandbox.io/s/intelligent-rgb-6nfrt3
It’s a great idea to decouple business logic from view logic, but then hooks are the wrong place to start. Last time I checked, you couldn’t use them at all outside of a React component. That’s just a terrible place to put your business logic if you want it to be isolated from the specifics of your view.
I’ve mostly moved away from React, so maybe this has changed recently, but it seems difficult considering the fundamentals of their design.
Josh Comeau has a nice overview of useMemo and useCallback, one of my favourites: https://www.joshwcomeau.com/react/usememo-and-usecallback/#w...
In other words, you're checking React discussions and finding discussions on how to maintain React code. What were you expecting to find?
> What happened with the simplicity of just "generate some boring ass HTML DOM in JSX, and it applies the diff to the actual DOM".
React happened, which does just that but transparently and effortlessly. In fact, React does it so well that a concern is to prevent it from applying those diffs when being updated when it doesn't need to.
> That's it. That's the entire value proposition of React and it needs no hooks, handles, states, immutables, events, data trees, properties, arguments, components, nothing else.
React does not need those features if you are using React for things other than developing graphical user interfaces, which by their very nature are stateful, emit and react to events, handle properties, etc.
How do you share data fetching logic across components
How do you share a common UI functionality like toggling states, starting timers, across components?
People are now more concerned about clearly writing business logic while stiching together React lifecycles methods, instead of the other way.
There exist design choices that would end up with a different combo. Class components with hooks or function components using lifetime callbacks.
Yes, hooks — basically sub components with possible effects and yielding values, or DOM output — are a terrific idea and much more functional and principled than explicit lifetime callbacks.
All the dependency arrays and non-conditional checks etc are because of the function components approach and don’t have much to do with hooks.
I feel nearly every discussion on hooks mixes this up and makes the whole conversation just weird and confusing.
And because of React's design choices. Reactivity can be achieved without explicit dependency lists.
Now I'm working on a gigantic React project, and I'm surprised it's still working. It's all based on function components with all the hooks, higher order components, middleware components, and tons of other stuff. It works, and it's clearly maintainable, but it's not pretty. Endless useEffects after each other make it hard to see what's going on. Every change requires changes in half a dozen files at least; DRY is clearly not a concern here.
I'm not a React expert, but I think function components and hooks were a mistake.
One thing that strikes me is that years ago everybody was excited about ES5 finally adding classes, and now everything seems to be moving away from classes.
I think JSX is still a cool idea and an interesting alternative to templating, but I also think that if I were to pick a frontend framework now, I'd go with Svelte.
Keep your functions small. Re-use is key - whether its hooks or components. Keep state sane by writing small functions that handle a couple state items internally, or create a parent state using context around a group of components.
React gets a lot of hate, but most of it is unfounded. It is just a tool. I see people write 800+ loc react components and wonder why it is "so confusing". The problem is obvious. The goal of using any technology is to make money, nobody cares (end of the day, just being real lol) about any of these esoteric practices that happen under the hood with effects, etc. Write good code and most problems disappear.
Unless you're working at Meta on react, or you have some burning desire to build tools like this (and honestly only <5% of devs who contribute will contribute something meaningful), there's no reason to pick so many fights with these tools.
Just use it by accepting its features and limitations, and craft your UI project well enough that it is maintainable and keeps printing money. Anything beyond that is a waste of time/effort.
This might be helpful https://react.dev/learn/you-might-not-need-an-effect
React does no such thing.
`this.handleClick` vs `c`.
I still use classes for building data structured but don’t think creating classes should be encouraged by a framework.
Does this actually matter though? It's going to be gzipped anyway right?
https://github.com/terser/terser#cli-mangling-property-names...
For me the key advantage is much less boilerplate, readability and portability. The problem with `Stateless` components up until the introduction of hooks is that if you wanted state you had to write your component as a class so you ended up with components written in two totally different syntaxes with one being much more heavy on boilerplate.
The last key advantage i see is it brought the "React Components" way of sharing to logic. Previously every piece of logic you shared had to be connected to a react component, so you ended up with many "Providers" that were just a div with logic. Now with Context and Hooks you can easily transport that logic without the use of a Provider (well you still need one with Context but that a slightly different story).
Deleted Comment
I don't agree with most of the argument here, to the point where I think we live in totally foreign echo chambers that rarely exchange ideas. I didn't get any new idea out of this article, it didn't inspire me to do something I already tried 10 times in the past.
The website loads fast, and that's great. 10% of the CSS is unused. and that's a small blog. In the non-themed CSS, it's close to 50% unused. You could consider it a non problem - at scale dead CSS is complicated to manage, at least for me.
I’m personally of the belief that we should assess arguments, not employer. Someone working on a competitor to React can make very valid arguments against it, they’re often some of the most knowledgeable people about the drawbacks of the framework.
I’m personally not a fan of Alex’s abrasive style but I’ve seen plenty of his critiques of sites written in React-based stacks and they’re usually evidenced with bundle analysis, burn down charts and so on. They’re not unfounded.
(I also disagree that Web Components are a competitor to React. Frameworks like Preact and Svelte are interoperable with Web Components and build on top of the API. React chooses not to but that’s neither here nor there)
Used to work on Web Components (the browser side.)
Although we didn't take it as a competitor, in hindsight it was - at least in a sense. Both are component-based technologies, and the expressiveness of React and ES6+ made WC less relevant. I think WC is still nice to have, but it is no longer a must-have as it was originally envisioned.
The JS ecosystem has largely solved the problem by themselves without browser vendor's help (besides improvements of JS itself.)
They may have been solving similar problems then, and they may be optimized for different things now. But Web components are a web standard, and React is not. Pushing for web standard technologies is inherently unbiased because that's just betting on the platform. This results in pushing for platform improvements (like declarative shadow dom so it plays well with SSR, etc), and then everyone benefits.
IMO it'd only be a bias take if web components were branded as having no issues whatsoever, or that they are the most optimal solution for everything. I think it's okay to say, "web components currently don't solve my problems and that's why I'm looking to use something else like React or Solid". However, I've not seen this sentiment shared when it's the other way around with React. It's always "no one got fired for picking React" instead of actually evaluating what will deliver the most value to your users.
There's a ton of politics around web standards, and you can bet if Google manages to push through Web Environment Integrity, I will not consider people suggesting to use it "unbiased because it's a standard"
Nuance doesn't matter to most proponents of web components. When they were introduced, for the first few years they were explicitly marketed as platform-native solution that makes frameworks obsolete.
Now the rhetoric seems more nuanced, but it's the same. It's only been upgraded to "build with lit".
> IMO it'd only be a bias take if web components were branded as having no issues whatsoever, or that they are the most optimal solution for everything
Mostly they are billed like that. And any voices criticizing them are either ignored or blocked.
React was invented because Facebook had very interactive/stateful UI as well as large teams of developers working on the same codebase. The then conventional jQuery soup approach didn't cut it.
Should the web platform come up with a standards-based approach to solve the same problem, then this is not "competition", it is a blessing. It's not like React earns Facebook any revenue. Ideally, it wouldn't be needed or exist at all.
I still remember the day when angularjs was a new thing(around 2015 perhaps) and as a newcomer I was sucked into it. Just loved the thing. A year later, there were news about Observable JavaScript objects. So objects could send a notification about themselves having been changed. And when do so, do DOM changes could be done accordingly, without having to implement a render algorithm and having to compare shadow nodes with new render results to see what changed every time any data change occurs. I don't think we are past that with React, and as the author mentioned there should be absolutely no reason for a developer to worry about rendering performance (the amount you have to use react, with for example useMemo, useCallback) and is something to be looked after and questioned.
Another argument of mine[0] would be the definitions that have been introduced by react. Component, state, hooks. It seems like we have forgotten about what they are actually called, and its function is in the context of programming (functions, variables, events, etc.). And so people become solely a React developer and can't really see a way out. (from the article: "And maybe—just maybe— your current satisfaction comes, at least a little bit, from simply not knowing what you’re missing.")
[0] - https://medium.com/@ngergo/describing-how-react-works-in-com...
i have a csv with one million rows. should i load the entire thing into memory and render 1m * column_count dom elements?
> Another argument of mine[0] would be the definitions that have been introduced by react. Component, state, hooks. It seems like we have forgotten about what they are actually called, and its function is in the context of programming (functions, variables, events, etc.).
a Component is a Component because it represents a node in the React tree. not all functions are Components.
state is state because it's more than a variable - updating it triggers re-rendering. a normal JS variable does not come with this reactivity.
hooks are not events. they are wrappers for reusable logic.