Things you forgot (or never knew) because of React
joshcollinsworth.com
joshcollinsworth.com
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.
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. <script setup>
const items = [1,2,3,4,5,6]
let runningTotal = 0
const getRunningTotal = (item) => {
runningTotal += item
return runningTotal
}
</script>
<template>
<ul>
<li v-for="item in items">
Item {{item}}; running total {{ getRunningTotal(item) }}
</li>
</ul>
</template>
No need for a computed property. Plus, getRunningTotal can be unit tested, or extracted to another file for reusability.It is just that above example is so short and readable, that you don't have to bother.
If you're after keeping the concerns separate you would need to precompute the running total for each item.
See also: mustache(5) which completely embodies this philosophy.
return (
<ul>
{someArray.map((item, idx) => (
<li key={item.id}>Item {item}; running total {idx + 1}</li>
)}
</ul>
);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).
<If cond={...} then={() =>
...
} els={() =>
...
} />
so the `then` and `els` branches only get evaluated if needed{ some_condition ? (
<H2>It was true</H2>
) : ( <H2>It was false</H2>
)Well, actually. it don't have to be. Just React decides to compile JSX in that way.
Vue 3 also supports JSX. But it keep the content of children lazily evaluated.
Their compiler compile a JSX `<Parent><Child /></Parent>` to structure like `h(Parent, {}, { default: () => h(Child, {}, {}) })` . So the child jsx tag is never evaluated unless the Parent component want to.
It's really not a syntax limitation because JSX never specify that the children of element must be eagerly evaluated.
That seems like a dangerous reinterpretation of JSX. It's just a literal syntax, it's not meant to be lazily evaluated.
Having a JSX compiler interpret <Parent><Child /></Parent> as h(Parent, {}, { default: () => h(Child, {}, {}) }) would be like having a JS compiler interpret
let parent = {
child: {}
};
as let parent = {};
Object.defineProperty(parent, 'child', { get: () => ({}) })
That's just... not what that syntax means. It should be h(Parent, {}, [ h(Child, {}, []) ])
Saying 'JSX doesn't specify it' feels like playing a 'there's no rule that says a dog can't play basketball' card.In practice, every framework interpret jsx in slightly different way. React has own. Vue has own. Solid has own. And even react itself interpret JSX in 2 way (the new and old jsx compiler). So I feel there really isn't a rule that you can't compile jsx in some specific way because the output is never part of the specification of jsx from the beginning.
Couldn't you put that in a function that returns the correct JSX element or am I misunderstanding the problem? Something like:
renderThing(number) {
if(number > 0) return <div>...</div>
return <div>...</div>
}
const Page = () => {
return <div>{renderThing(someNumber)}</div>
}
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.This is because it doesn't get registered as it's own component, so conditionally called children with hooks may cause errors.
So this style of code is fine in react
Ternaries, booleans that cast to JSX, switch statements wrapped in IIFs...
When it comes to comparing React with Vue or Svelte, the templating is not the critical factor.
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(...)`.
I did only use `v-for` as an example of sorts though, and in the common case, `v-for` vs a regular `for` loop are similar if not the same, IIRC, but in some cases where your children may show or hide based on downstream data, it can be more efficient
> 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
I've done a lot of Vue and your bit of React and overall I prefer the Vue way here.
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...
Have... Have you seen the roadmap for web components? 20 more specs just to barely patch holes in the original design: https://w3c.github.io/webcomponents-cg/2022.html
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.
On change detect new file is there, Set file to variable, Call api to save state.
The issue is setting the variable and calling save is now a race condition.
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`
What about things like real-time (pushed preferably) updates based upon db changes, or another API finally sending streaming results, etc
- 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
Go is backwards compatible.
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.)
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.
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.
Literally not one argument here that makes any point.
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 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.
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.
render(props) {
return(
`<div>
{props.value}
</div>`
);
}But please, build something proper with just that and presumably a .innerHTML = ...
Let us know how it goes :)
But with a "tagged template" it should be easy to treat the variables before actually doing the templating, without making the code ugly.
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.
Angular doesn't separate concerns at all, it just ties it all together with an entirely new and un-intuitive DSL that you have to now write in the HTML.
Just look at your DSL here: https://angular.io/guide/binding-syntax#types-of-data-bindin...
You abso-fucking-lutely are writing code in your html, you're just writing a crippled version of their custom DSL instead of plain old javascript.
Frankly - I much prefer to write plain old javascript instead of learning a new bastard language that isn't useful anywhere else.
JSX achieves that relatively well. It's not entirely plain old javascript. But it's about as close as I've seen anyone get for a template language complete with data binding.
EJS https://ejs.co/ was my pick before JSX. For similar reasons - I don't want to have to learn a dsl which is just a shoddy wrapper for the JS anyways. Just let me write the damn javascript.
I’m very fricking close to this with web components and default Vite build. The only gotcha is having to bring along a few utility classes I wrote that glued it all together. Fewer than 40 lines.
Why is this important to maintain? People have been complaining about this since the beginning, but I've never seen anyone actually articulate what the problem is.
It seems to me that progressive enhancement was a genuinely great idea, but somehow the true concept got lost. Nowadays some insist it's ok to have a site that won't begin to do anything without JS, but at the same time it's not OK to mix JS into the HTML code. That somehow we're preserving the purity of HTML as a display layer just by putting it in a separate file.
Do not show me a UI if it doesn't work when I press/touch it. More, if I visit your site and your UI doesn't present itself within 1-3s, there should be some alternative UI presented that explains why (rather than just a white page).
So PHP?
Mixing html and code is a pretty old paradigm.
> were doing "JSX" a decade before React arrived
is another instance of "rediscovering old paradigms". What I'm not saying is that this method of building a view is unnecessary, or wrong.
> If so, other than what I described (web components) how would you build a view?
There are many ways to create a view. Programming history is littered with them anywhere there's a UI to be created. Will they interact nicely with React? Probably not most of them, but it doesn't mean they do not exist.
I've previously updated some components in a design system to Vue 3, where I followed the HTML results set by the React implementation. Reading the Vue 2 components worked almost immediately. The React components were so over-complicated that I sometimes literally had to follow the browser inspector instead of understanding every twist and turn in the code. I have never seen a Vue codebase that is as unreadable as the average React codebase with mixed business and presentation.
I'm taking about HTML/JavaScript front-ends. The ideas behind JSX go back to at least 2004 when I first began using that paradigm.
On a separate note, the attitude of "That's back-end" that permeates HTML/Javascript development is probably one of my biggest pet peeves; the disdain for what programming languages and GUI implementations have offered in the past hinders learning lessons from those implementations.
And that only holds us back.
I disagree. I believe you're referring to the paradigm of mixing markup and code, which I never did.
Also, GUI development has traditionally been a shit show. From Qt/WinForms to WPF to now using Web tech because the whole industry threw up their hands. There's MVC, MVVM, MVP, you name it to describe a proper UI->data relationship and all have failed to breach the boundary of their domain. Components, like ECS in game dev, are one way of solving this issue. Because we have to separate our markup from our logic we have JSX. I really wish I could do something like:
this.view.set(<div></div>);
but the reality is this. If you're developing a UI using code, you don't need markup at all except for the specific element/display you are representing. Almost all of my webcomponents are just a div in a document.createElement and the rest is built up using the same. document.createElement. It's tedious, it's error prone, which is the argument for JSX. I don't need to create a Nav component and a Nav Bar component and a Nav Item component and a Nav Menu component, etc. I can just create a Nav Component and handle it all from there, simplifying my UI view code.In the end, all of these work arounds are simply because we have to deal with the final product, html and we (myself included) get stuck behind the default tags because thats what we know. We don't need any of it. Define your own. Treat the page like it's one giant empty xml document and everything's derived from a div and see if the browser treats it any different. It doesn't. So your entire body could be made of:
<article>
<post>
<post-title/>
<post-author/>
<post-body/>
</post>
</article>That seems like arguing you don't need functions in your programming language and can simplify it by inlining everything.
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'm not convinced that people are building integration APIs for consumption by external code. That means no JS events (redundant since it uses stores or signals and whatnot) and minimal callback availability to hook into a component state.
One might not control the code if this is from an open-source library for instance.
Maybe the premise is "don't do that" , but then people still wanted WebComponents at some point. So seems there exist use-cases for component interaction. Or were people mistaken in the first place?
this doesn't happen in practice... like at all...
is your implicit assumption that anything written in react will automatically work just fine with svelte but not the other way around? why would react -> svelte be any easier than svelte -> react, and why is the burden on React to solve interoperability problems between competing frontend frameworks?
Of course it can't happen if it's not easily if at all feasible. That doesn't mean that people don't want to do it.
The fact of the matter is that it seems to me that WebComponents are an attempt at solving an interoperability issue. Or am I misunderstanding?
I own both sides of the stack. Say I have a react component that happens to mount a svelte component in the DOM.
I expect Svelte code to be running somewhere (I wanted to use a svelte component, I have to initialize that stack).
I expect React code to be running somewhere (The main page is react, for example).
I expect to have some sort of signaling or state management solution (say a redux store, since the main page is react).
I can just update the redux store from both stacks. The store emits the correct events whenever it's updated - all subscribers are notified - react-redux does its magic and conditionally re-renders my react tree based on the new state.
I can do exactly the same thing in Svelte - subscribe to store events, see an events when react changes something, update my svelte app in response.
---
And it's absolutely not limited to redux... I can do the same thing by hand with global state, or by emitting custom events in the DOM, or any of a hundred other ways to get these two apps to work together. I own both sides - making them play nice is normally trivial (if not always quick, and sometimes tedious as all get out).
That's the whole point of the question.
Sure - each library is going to do its own thing with regards to how it manages it's internal DOM and state, but that does not matter at all.
All you care about in wiring them together is:
"Can I call some js code in response to state change in svelte?"
and
"Can I call some js code in response to a state change in react?"
and the answer to both is a resounding "Yes!".
So now I can easily make the state of one visible to the other... I just run some code in response to a change on either side that updates the state of the other - done.
If you want to get adventurous - you can automate the entire thing away with a proxy store, so it happens everywhere by default.
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.
It is very small and very quick - one of the fastest frameworks out there - but also not too complicated or lean. The signals system takes a bit of getting used to, particularly if you're coming from the React world (e.g. there are no render functions, rather each attribute is reactively updated when its data dependencies update), but it's also incredibly powerful once it clicks. Also, once you get down to it, almost everything is just native browser elements, so if you need to integrate with another tool or library, it's usually really obvious how that should work.
https://github.com/AlexErrant/Pentive/blob/main/example-plug...
Solid JS!
{#each {length: 3} as _, i}
https://stackoverflow.com/questions/58213585/svelte-3-how-to...Or do you create an array of JSX-elements, like
let elements=[]
for (let i=0; i < 10; i++) {
elements.push(<li key={i}>I'm number {i}</li>)
}
return <ol>{elements}</ol>;
Does not seem like an improvement to me.Josh Comeau has a nice overview of useMemo and useCallback, one of my favourites: https://www.joshwcomeau.com/react/usememo-and-usecallback/#w...
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.
You don't always need this. Sometimes your business logic can just be a pure function. But where you do (and IME this is quite common), hooks are super nice.
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
There's no reason to reset before setting data again, and I'm not sure why you'd even consider putting the functions in the dependency array for the useEffect in usePets.
I can imagine reasons you'd want to setData in a useEffect (maybe when something else changes, or the user performs some interaction, you fetch new data and then set it), but the dependency would be the thing that indicates that action has happened, and not a reset function returned by a custom hook coupled with your data and setter function.
The point is not that this code is good or bad. It's that it is possible to write such hard to predict code.
Remember this is a stripped down version of some code running in production.
Now to address your specific points anyway: "There's no reason to reset again": in the non-stripped down version, the hooks rely on a third hook (let's call it "useToken") and needs to react accordingly to this change of token to fetch new data
"I'm not sure why you'd even consider putting the functions in the dependency array for the useEffect in usePets.": unfortunately react-hooks/exhaustive-deps is here to warn you. You can disable or ignore it but I guess you expose yourself to a real missing dependency? Genuinely very keen to hear if you use this rule in your projects and what you do in such cases (where you use a function in the useEffect but do not want to re-run the effect each time this fn changes). To me it's such a weird/unnatural thing to list functions as dependencies because almost all the time functions do not change.
> (The identity of the setCount function is guaranteed to be stable so it’s safe to omit.)
Maybe in JS it still warns in your example because setData is passed in from calling useResource, but at least with Typescript I'm pretty sure eslint infers this
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.
But there's another option: don't use React as a framework, use it as a library. And do your modules/components/reuse/fetching in your own plain code, while using React as a display layer. You don't even have to use React for the entire UI.
This is a silly argument to make. People don't want to onboard onto a myriad of little reinvented wheels just to put together a GUI. This is well known to be a major mistake, and the root cause of failure of countless projects.
People are paid to deliver features and fix bugs, and not to peruse through npm like they are playing Pokemon. React solves their problem by solving developers' problems. Don't you understand the value of using a standardized tool that answers all your problems?
Knowing how to architect your app remains important, and once you know it, it's trivial. For those who refuse to learn it because they deem it a gargantuan task, frameworks will keep trying to provide a "generic" solution, but a "generic" solution is by necessity overcomplicated, overengineered, and bloated, because it's trying to address EVERYONE's concern and specific needs.
At no point in time will a monolithic "everything solution" be simpler than a specific modular solution to a specific modular problem.
React started with the promise of simplicity, and being a library, not a framework. Somewhere along the line this ideal was lost, this happens often. And it happens often because many small elegant solutions start with the intent of replacing the status quo bloated behemoth framework that everyone hates. What they don't realize is that with lack of understanding of why frameworks end up like this, this is the fate THEY will share one day. Entropy is a b**ch.
Online forums dedicated to frameworks are filled with questions on what the framework does and how it works. No news there. What did you expect?
> Knowing how to architect your app remains important, and once you know it, it's trivial. For those who refuse to learn it because they deem it a gargantuan task, frameworks will keep trying to provide a "generic" solution, but a "generic" solution is by necessity overcomplicated, overengineered, and bloated, because it's trying to address EVERYONE's concern and specific needs.
I'm sorry, you typed a lot of words to actually say nothing. So you don't use all features provided by a tech stack. So what? That is not bloat. Writing software is not a game of bingo.
Also, reinventing the wheel when a fully working and tested wheel is already available is a very dumb mistake and a fundamental failure in the decision-making process.
> React started with the promise of simplicity, and being a library, not a framework. Somewhere along the line this ideal was lost, this happens often.
I don't think this is remotely true in any way. Undoubtedly React greatly simplifies the work of putting together working and full-featured SPAs. The concept is so good and so extensively proven that React is already being used to develop native GUIs in desktop applications.
Your comments reads as if you're tilting at a React windmill. It's ok if you like vanilla JavaScript, but you're not being honest with yourself if you're failing to understand what problems React solves, how well Reacts solves them, and why the whole world has basically standardized around it.
Interestingly enough, React is probably the only major frontend framework that is obsessive about backward compatibility.
I had to pull a component from an internal project into my codebase recently. The component was still class-based. Worked without a hitch in the modern hooks-only code base.
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.
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.
`this.handleClick` vs `c`.
I still use classes for building data structured but don’t think creating classes should be encouraged by a framework.
https://github.com/terser/terser#cli-mangling-property-names...
Does this actually matter though? It's going to be gzipped anyway right?
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).
No, not at all. Any nontrivial component is going to have some sort of conditional rendering, but whether the inputs are supplied explicitly as function arguments or implicitly as state is for the most part orthogonal to what you do with them.
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.
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.
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"
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.
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’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.)
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.
On my part, I never jumped on vite, because the only argument I've heard for it, is faster dev builds. But my current builds are fast enough (I grew up with 40+ minute compile/link cycles in C++).
And I don't have a week to change my current scaffolding. If you do things right in your company you never have a week to change such a tool. Because that's a week you could spend on relevant features and bugs. Heavily advocating tool changes are fast-track to become a "problem engineer".
Also, yes, React has aged very poorly, and even more so, the ecosystem around it is rotting hard. It's moldy.
But it's still very good and is almost perfect. Maybe instead of writing a new framework, we should consider doing a React 2.0 with batteries included.
Besides what's already in NextJS, what are the batteries you're thinking of?
Sometimes the tools suck, and sometimes you need to improve that situation, ideally in a gradual fashion. Sometimes they're passable, and there are other priorities, but usually tools start showing their rust eventually.
I also think it's extreme to say it's aged "very" poorly. It provides a relatively productive way to express UI as composable state machines, and now it just has a solid ecosystem of viable competitors.
> I never jumped on vite, because the only argument I've heard for it, is faster dev builds
I wouldn’t assume Vite is worse than its competitors for UX just because it doesn’t explicitly say it’s better
This is the calculus. Vite isn't built for the "lone ex-C++ dev" shop. Its built for teams that can run this calculus and realize that, 80% of the time, investments in speeding up the software development lifecycle are among the highest leverage, most direct correlates to productive output a software shop can make.
My hobby of doing game dev (driven by automated testing) has taught me so much about patterns of abstraction, boundary making, and modularity. Domain driven design makes so much more sense given my stint in hobbyist game dev. (buyer beware: game dev pedagogy is awful and many lessons I’ve had to discover myself)
In my day job as a web dev I notice that my team/company think exclusively in our framework and we seem to push everything into the framework. I wish we treated react as just a view layer but so much more gets pushed into react. We’re so hooked on the sauce that writing anything outside of react is defacto considered an anti pattern.
I know there has to be a better way but before I can know what that is I’ll have to understand why people adopt what I’ll call “framework brain (rot).” I kinda suspect programmer pedagogy is fueled by clickbait pretenders who find it easier to teach frameworks than the tough stuff like how to make a complex system easy & practical to build. Let me know what your speculation on this subject might be.
I'm kinda curious about this. Do you have any good resources on automated testing for games?
If you ask about automated testing for game dev you quickly learn there is very very little desire to entertain the subject. I’m unclear why.
At some point I’d love to share my insights as videos and/or a blog series.
There's a lot to balance making these decisions at a project's inception. NIH bias can cost you a lot for no benefit beyond self-satisfaction. There's a good chance making something with a current stable framework and migrating to a new one down the road will have taken far less time than making the initial RYO version. You'll also be able to hire people who already know how a big chunk of your codebase works, and lots of your underlying functionality is already documented.
Additionally, pedagogy is very different from practice. Most of the time when young me decided to do something the hard— but "more elegant" and "simpler" "more correct"— way rather than using a library or something, it was because I didn't actually know how hard the hard way was. Those are mistakes you only make once. It's true that some people use frameworks because they don't understand how to do what frameworks do under the hood. A lot of other people use frameworks because they know exactly what it takes to recreate what that framework is doing under the hood.
That obviously doesn't work if your code uses very little of what the framework offers— but they are generally designed to bring a lot to common use cases, and can save you vast amounts of time, energy, and money if judiciously applied. Just like any other tools, they've got their good use cases, bad use cases, and ways to outright abuse them. A good understanding of your requirements, the preferred methods to address them, and the current tooling available is the way to decide which of those scenarios a framework would fit into.
It's like C developers smirking and demeaning web developers because "kids these days don't know anything about computers or memory management" as if they truly believe that that's true because newer devs aren't smart enough to understand it, rather than the ground truth that it's just not relevant to those newer devs, and that they could easily learn everything the jaded C dev knows, if it became relevant/useful again.
I definitely believe that a devs exposure to various languages/frameworks is important though, even if they only work in one domain. Someone who is a React dev will try to apply a React spanner to everything they do, but then again someone who is a C dev will write C-like React code (or just outright refuse to engage in web dev).
I think it takes a special kind of person to grok C and C++. If offered C/C++ on the one hand and JavaScript/Python on the other, very few people in the world will choose C/C++.
Back in tha day, when C and C++ were the only games in town (and programming wasn't as lucrative), the industry naturally filtered for these people. Today, it lets more people in than ever before. These new people, it can be reasonably argued, are not as smart as those select few from yesteryear. The fact that they're not exposed to the mind-scrambling vagaries of architecture differences, which means the barrier of entry and attrition rate are far lower, should pump that intuition, no?
ecosystem is king
So you refuse to work with people who do not want to re-invent the wheel for a shiny new framework because it is "better"?
if you don't want to reinvent a feature that another framework has a solution for, then i'll ask you to show that this other framework solves more problems than the current one, and it's worth the cost of switching (or switching back).
but, like you, i don't like to switch to a new framework just because it promises to be better.
i prefer to avoid switching frameworks as long as i can. i'll only switch in a project when i run into a problem that the current framework can't solve at all.
Less popular platforms will get more isolated rather than less as the wave of generated code that “works out the box” only works with stuff like react…
To elaborate further: I don't believe ecosystem is king. Success can mean different things to different people, and is not always a single dimension of "popularity units".
> I’ve had to deal with a nightmare Elm project. The difference is, I know what I’m doing. I solved all the problems, created examples to lead other devs and everything was fine. Have your company contact me if you need help.
I’ve had to deal with a nightmare React project. The difference is, I know what I’m doing. I solved all the problems, created examples to lead other devs and everything was fine. Have your company contact me if you need help.
shipping as wasm is not an option as it increase bundle size for very little gain (unless you're running something super performance intensive).
We would need a bridge between sane languages and a JS framework, not just JS in general.
5 years ago I would have done a Haskell -> hyperscript bridge to build frontend applications. Today I would do a Rust -> Solid.js bridge to build frontend applications.
Logic could be compiled down to JS, UI could be compiled to Solid.js components.
Source: 7 years of Haskell in production
Not a single bit of "React" in the code. It has absolutely NOTHING to do with React. But I've seen it in projects I've inherited... just because, "we're using React, may as well get the React version of the library".
Likewise Svelte is mature and well understood enough that like React, enough nobody could get fired for choosing it either.
If only the article had dedicated a section to how React trained us that things need to be built specifically for a certain framework, and how no other modern frontend framework is as stubbornly incompatible with the platform as React is.
This isn't really any different from frameworks in general: JQuery had its own massive ecosystem that assumed JQuery was being used; trying to use something from the Rails ecosystem in Padrino was unlikely to work well; Vim vs Emacs; etc etc. Frameworks accumulate ecosystems around them and have since pretty much the beginning of programming — I don't think React has nefariously trained ecosystems into the community; I think people tend to build libraries on top of other libraries they know, and React is popular, so it's the basis for more libraries (the ecosystem).
Probably because they had already moved on to do the same thing at some other company for more money.
Programming languages are always laughed upon and most of the time I hear frontend developers telling me that frameworks are what's important, not the language. But I think typescript shows how impactful a better programming language can be.
Unfortunately, even typescript - despite of how great of a language it is - isn't capable yet to support even basic cases.
For instance, using the features of the language to describe a nested structure of components, each of which has different dependencies that are a subset of its parents dependencies. Such a thing cannot be expressed with typescript, so frameworks/libraries all come up with their own way of doing that and in consequence giving up on typesafety and hence making it way harder to understand things and way easier to make subtle mistakes.
I hope we will see major improvements on that front eventually. However, powerful programming languages are hard to learn and take time to master - something that is often doomed to not survive in the frontend world where things are fast-paced.
> there can never be real progress ...
> without having a programming language that is powerful enough
Historically there have been plenty of interesting powerful languages on the periphery, but most of the useful stuff is not written with them.
I may be misunderstanding you, but this seems tractable with React.memo. Merely encode the dependency or lack thereof in the propsAreEqual predicate.
I think so, but I probably haven't explained it well. Let's assume the following structure:
<Outer> <EditListElements> <UIElem>1</UIElem> <UIElem>2</UIElem> </EditListElements> </Outer>
Let's say EditListElements is a generic 3rd party component.
How does the definition of the props/dependencies of the elements look like?
I would like it so that when I define `Outer`, I define some props that outer needs (e.g. let's say it needs an A and a B) and then the actual props to initialize it become A, B and <Props of EditListElements>. But EditListElements is a 3rd party component, which itself derives its properties based on the children it uses. And so on.
One of the reasons to do it like this is that if I have a big, nested graph of components and I add a required dependency value to some component down the graph then all the intermediate components should have the props "automatically" updated and I will have to pass it to one of those components (potentially the very toplevel component) to satisfy the compiler. Then, it will be passed down automatically to where it is needed.
The way this is currently "solved" in react most of the time is to move those required values to some global store or so which is then accessed or at least accessible by all components. It quickly leads to a big ball of mud and it is tricky to see what a component needs (and what it doesn't need) by just looking at the component in the graph.
Hope that makes it more clear.
- React launched
- JSX became the official recommended way
- CSS-in-JS became the way
- Context was invented
- Hooks were invented
- Server-side components
Today I learned what a Web Component was, and there's a lot more boilerplate and manual copying of properties than I'd like, but it seems better than digging around in the DOM with JavaScript.
You all have my sympathy. It would be so much easier if we could just run mobile code without having to worry about all of the side effects it could cause. (Including the extreme side effect of taking out our systems completely).
As long as it’s necessary to re-invent wheels by building basic widgets from scratch, there’s going to be limits to how good the developer experience of front end web can be, as well as high churn because the common base that’s being built upon is so tiny. It’s like building a skyscraper atop of a food cart: technically possible, but all “solutions” are so stilted and full of trade-offs that there can be no consensus and inordinate amounts of energy get burned on constant re-engineering of the stilts.
This is pure insanity, we left those in the dust decades ago. Those were horrible interfaces.
React is bad is youre bad. Its much more fundamental than other frameworks. It also paradigms shifts from imperative to (more) functional. So if you are not comfortable with closures and side effects (like the author), you will get lost.
None of the pattern from any framework is new. Theres only so many ways to design systems, you either use callbacks, observers, or events. All have their pros and cons (where imo observers and events are inferior due to their quick branching factor in larger codebases). React gives the option to use any of these.
I don’t think it’s that simple. I write in a functional language for my day job, yet React hooks style components still give me headaches because they are leaky abstractions where you have to know what they’re doing under the hood anyway.
This argument feels a lot like 15 years ago when C++ developers were saying C++ is bad if you’re bad. Some are probably still saying it, but its pitfalls and crippling complexity are pretty widely acknowledged at this point.
1. Starts talking about empiricism, does not actually deliver on it
2. Talks a lot about how React-things are old-actually, and then talks about signals and two-way data-binding as if there wasn't a time before React where these things were also pushed. React's non-adoption is not an accident I think, and these kind of posts would be more interesting if they would leave the surface-attacks and actually engage with the philosophy behind React's approach[1].
3. Quoting Alex Russel suggests you are more interested in heat than light (which is what he is known for where I'm from)
4. Distorted guitars are good actually.
[1]: https://gist.github.com/sebmarkbage/a5ef436427437a9840867210...
> Quoting Alex Russel suggests you are more interested in heat than light
I know he's said a lot of harsh things about frameworks like React, Css-in-js, etc, but I've read all of them from the perspective of "these things are hurting the UX a lot more than you think".
"Stale closures in Hooks are confusing"
Seb gives an example under that section that they call confusing. I don't understand why. The syntax makes it very clear when the values are checked - if its in a closure, its clearly at the time of the click - if its not in the closure, its clearly at the time of rendering, so no, they are obviously not equivalent.
The problem with React hooks is that they behave very differently from all normal JS code. In normal code, most functions that contain closures in them run once and the closures run zero or more times (depending on the consumer of those closures). In React, the render function runs many times, but the inner hook closures run a different (could be smaller, equal or greater) number of times, where that number may depend on the number of times render runs or the number of times other closures run.
You can easily create a mess this way; React realized this, which is why the official documentation recommends not modifying state from within useEffect. But current frameworks (e.g. Remix) already do this, and this already causes problems with batching (see https://twitter.com/oleg008/status/1680290734644002816). Additionally, dependencies between multiple useState and useEffect calls can easily be non-obvious - they may be embedded within custom hooks.
In a mutable / signal based framework that really pays attention to all these details (like MobX) there is a consistent way to how things work based on a relatively simple dependency tracking mental model (MobX based signals can be implemented in about 50 lines of code if we're willing to forego the nice proxy syntax). So not only is state management way easier, its also on average less prone to these kind of issues.
In essence, React state managements makes things harder with the promise of making state easier and more consistent to manage long term, but doesn't really succeed in delivering on that promise. At least not when compared to more newer interations of mutable reactive state management (like MobX) which support all the goodies (automatic dependency tracking, automatic batching, automatic disposal of unobserved state and computed values etc)
I don't think I agree with that generalization. I probably could not even make a generalization about what normal closur-ing does or should look like.
> In a mutable framework that really pays attention to all these details (like MobX) there is a consistent model to how things work. So not only is state management way easier, its also on average less prone to these kind of issues.
My experience with MobX and the greater observable-industrial-signal-complex is that accidental loopiness very much can and does still happen. I have seen codebases with complex MobX computed-changes-graphs that senior engineers were clever enough to write but not to debug. And I was not aware of tooling which helped keep these graphs in line.
That said, I agree React's hooks have friction to them. I just tend to be in the camp of "I prefer my computational change graphs to be gated by a bit more boilerplate".
My experience is completely the opposite. I've worked on large, complex interactive editors writtein in MobX and its been pleasently easy to reason about. Some tooling is built into the framework (cycle detection, strict mode). The design guides you towards making the right choices (prefer computed over autorun, etc) and makes those choices easy to use.
And unfortunately, with useState, useMemo and useEffect you can make the same cyclic dependency spaghetti (e.g. useEffect can easily setState). Unlike with MobX however, everything is harder.
Some other methods for tracing and debugging complex graphs are described here https://mobx.js.org/analyzing-reactivity.html
I vaguely remember my colleague having a reason for why his abstraction did not fit in the computed box. Probably something related to async, so it might very well have been because of that
> I probably could not even make a generalization about what normal closur-ing does or should look like.
I would say the key reason why this looks so wrong is that it essentially breaks lexical scope. The closures "look like" they are the same values from the scope above, but they are actually values from previous runs.
I would be hard pressed to find another library API that breaks lexical scope reasoning for its closures in such a way.
useMemo memoizes a single value/"variable" for the most part. useCallback memoizes a function.
This article feels much the same.
IMHO, you can't have one (testing and licensing) without the other.
And why wouldn't they you can create a problem out of thin air, solve the problem poorly selling the solution, and then when your rushed, half assed and bad solution has issues, you can simply sell the fix to that as well.
I doubt we will see much progress in the quality and rigor of software engineering in the near term, it will need to take a shift from making money in the short term at any cost to making a quality product. Instead we see the same thing happening to other industries so I hold little hope in the near term.
Frontend work is unglamorous to a lot of developers but part of the more academic appeal is that it's still very much in its awkward teenage phase. That makes it appealing to tinker with and try to find a "better way." That's the churn.
> disproportionately composed of young and/or new and/or self-taught developers who "discover" new paradigms constantly
I've been there since the start, too. I disagree that it's been like that for that long, though. JavaScript was an awkward add-on at first, then a barely usable tool (early vanilla), then a stopgap measure to fix browser compatibility problems (jQuery, moo tools, underscore etc) and start to flesh out some libraries.
But the Angular/React phase was the first time people gravitated toward using the frontend as a proper language. Before then it was just a thing you had to deal with.
So 3 decades? Nah. 2 decades of "why do we have to deal with this" and 1 decade of "ok let's make this work somehow"
Don't forget Backbone which preceded Angular by checks 7 days.
I imagine an alternative history where good distributed software got traction.
I have to be honest I don't know what you mean here.
The web and its frontend (and tooling) is what this thread is about. We've thrown out a lot in the mean time. Java applets, Flash/Shockwave, ActiveX, dynamic HTML ... the web has grown a lot and will continue to do so.
But the world of JS as a front-end application language is still fairly new. Until the late 2000s it was just a bolt-on for doing little things around static HTML.
There's plenty of novel stuff out there, it just takes a long time to filter down to the mainstream. React hooks are probably the best example here: they're a crude approximation of an algebraic effect system from the early 2000s.
> Things you forgot because of React
Ah, this is going to be a back-to-basics, here's how great vanilla JS, HTML and CSS can be.
> I used to only listen to new music, updating my tastes with each week, and was never really satisfied. Then I discovered that there were certain genres that didn't update each week, and were timeless and satisfying.
Ok, this is definitely a back-to-basics, don't jump on the flavor-of-the-week
> React is old news now, here are a dozen new flavors of the week.
Wait, what..?
His kid is... drumroll... 4 years old.
I wonder what causes this (except me being old, but still, I thought this even when my oldest 4 as well).
Buy a green banana. Buy a certificate of deposit. Plant tomatoes. Cellar a bottle of wine. Plant a redwood tree.
I've found it helps for scale and as a bonus you get to see how a wine really ages over time.
Most bottled wines are meant to be drank right after bottling or in up to 5 years, white wines less than that. They get more brown or orange as they oxydize. Prosecco and sparkling wines are usually better if they're from the previous year.
I've had exactly one bottle of white go bad on me and it was somewhere in that 8-10 year range. It can definitely happen and would not recommend a white for this kind of thing . . . but this is also how you learn.
For someone not wanting to go the "make it yourself" route, I'm sure if you went to a good wine distributor and said you were looking to buy two or three cases of something you want to cellar for a good long while they would be happy to steer you in the right direction.
A change, it had to come
We knew it all along
We were liberated from the fold, that's all
And the world looks just the same
And history ain't changed
'Cause the banners, they all flown in the last war
- Won’t Get Fooled Again, The WhoAdvancements to CSS have made front-end way more reasonably than they were in the 90s. Stuff that took weeks to figure out with tables can now be done so quickly with `display: flex` and the whole grid system. It's beautiful.
If we had `display: flex back` in 1998 I probably wouldn't have stuck with FE rather than dive into the backend.
Of course those solutions don't solve the transition between desktop and mobile layout (since that wasn't a thing back then), but more some modern frameworks solve that well (like whatever MS calls UWP right now) without forcing everyone to reinvent a way to do infinite scrolling without running out of memory
fyi folks, Flash is also based on ECMAScript! just because the mid-90s tooling built by Macromedia triggers your nostalgia doesn't mean it was better!
float: left;
Oh wait… that was 2002 at least."Tables ought to be enough for everyone."
There we go! Nailed 1998!
* Webapps don't need to be installed
* Webapps work on all platforms without vendor lock-in
* Webapps aren't trusted and get sandboxed by default
and a bunch of minor victories along the way (you can right click -> inspect every webapp, APIs generally exist and have entered the cultural lexicon, cross-site SSO exists and works).
At the same time, a lot of the UI tooling and APIs feel like we went back 30+ years. Everybody is still reinventing the pop-up menu button (aka “select”). I really thought this was a solved problem in NeXT by the early nineties.
Was true of what I was doing in 1988 too.
The web has developed immensely since the 90s.
If some UI you use is slow it's certainly not because of the excellent frontend/web technologies we have today.
There are certainly many things to complain about regarding the state of the web but the frontend technologies are not to blame.
I disagree. Since I started programming some 20 years ago, I relearned web (and especially JS) every 5 years or so. And each time I was pleasantly surprised at how much simpler / elegant / clean things have become.
> that they feel slower to me as a developer and as an end user.
that's true though.
It possible (and even simple!) to make web-apps that are almost just as fast, but no one does that (at least not in the main stream).
I feel like the churn has gone down over time. But maybe that is also a decrease in my personal interest in front end as well as posts here (I recall there used to be a lot more frontend related posts here ~10 years ago)
We considered React but the landscape was also full of Angular and Vue and a bunch of others I don't remember.
At the end of the day, we went with the latest version of our boring server side rendering library that the rest of the app used. A huge reason was the churn in front-end javascript libraries.
I've never once regretted that decision and the project was a big success.
Boring tools are the best thing ever. What did you use?
Very boring but there was so much technology change already in this rewrite that we chose to limit the amount of new stuff for everyone to learn especially when we didnt know if it would be applicable to anything in their future career.
Wow, you made architectural decisions based partly on optimizing the employees career development? Kudos! I’m not sure how common actually investing intentionally in engineers careers is?
Personally, I know many developers who are doing great work with frontend technologies. Some with little experience, some with decades of experience, some self taught, and some with formal CS degrees.
Frontend is a great career path for those who enjoy it.
Web ships with barely anything and when it does have something like Date handling people still write replacements for it because it's so bad.
It would be like car guys spending more time arguing about whether Snap-on is better than Craftsman than actually talking about and working on cars.
I thought the SnapOn koolaid was stale fifteen years ago. Turns out no.
most of us don't. these comments are mostly from people whose idea of "web development" is a form and some static content.
That conversation accelerated the first ten years of my career by making me more effective. I knew people who made it farther with less work than I did, but mostly I knew the reverse. So I in turn have talked about the pendulum swing with more people than any other topic.
In the Expanse, Amos talks about The Churn, which is a related phenomenon.
“When the jungle tears itself down and builds itself into something new. Guys like you and me, we end up dead. Doesn’t really mean anything. Or, if we happen to live through it, well that doesn’t mean anything either.”
If you come through chaos unscathed it doesn't mean you were good. It just means you were lucky. Don’t let it go to your head.
The motivation of people with 3 years of experience is to jump on a bandwagon that mutes the effectiveness of having 15 years’ worth of experience. You’re dragging half of the industry down in order to pull yourself up. That’s defecting, and we all know how that turns out.
Svelte's the real deal. How do I know? Because it's not a new API or paradigm. It's the old web just better.
It encourages HTML and sane CSS, not just wrapping them in endless boilerplate. It compiles to efficient code rather than making you write all of it over and over again. It takes all the lessons from the last decade and a half and distills them into familiar web development patterns.
<script>
<style>
all your HTML
+ bare minimum of logic to solve your problems
I haven't been this excited about a new web technology in a decade, so coming from an old school web dev who learned off of view source in 1996, take that into consideration.And while I prefer Svelte, Htmx is doing a lot of the same work; not new APIs; just embracing old ones without all the boilerplate.
Other than that, for web functionality, they're identical! ;-)
Then of course there's the ability to supplement authentication on the backend, detect file uploads for background processing, etc. All of which are outside the scope of FastCGI.
But you don't care for Lambda. That's fine. You do you.
https://gist.github.com/Rich-Harris/0f910048478c2a6505d1c321...
https://svelte.dev/docs/svelte-components#script-3-$-marks-a...
https://svelte.dev/docs/svelte-components#script-4-prefix-st...
"It takes all the lessons from the last decade and a half and distills them into familiar web development patterns."
That includes reactivity and state management—two concepts that weren't adequately covered by the old web.Things only get worse when you add vanilla javascript to the mix.
Or… you could use the tags most appropriate to the problem with accessibility and SEO automatically coming along for the ride.
PicoCSS is an excellent example of what can be accomplished with just a sprinkling (~10KB) of CSS over plain old HTML.
Browsers can do so much more than they used to out of the box today. We should take advantage of that rather than silo it away in one-off React-based APIs.
You may disagree that html and css are that bad. But I think it was always a mess, specially when you go beyond linked documents and add any kind of interactivity and forms. There's also inherent limitations like "select" dropdowns offering very little functionality and mostly ending up as custom components in all projects I have worked in.
This is not at all the case. I highly recommend actually looking at Svelte examples before commenting further.
That said, there are a lot of folks out there who don't know that, for example, combo boxes and accordions are possible with plain HTML.
<datalist>
<details>
<summary>
PicoCSS is a great resource for seeing what's possible with just plain HTML and ~10KB of CSS.Folks aren't against solving problems. I think the main concern is the amnesia regarding problems that had already be solved and are now be solved again only not as well.
It's a feature, not a bug. That said, I personally prefer the Svelte model. I like leveraging the client browser for effect, not just rendering everything server-side.
React really made people think they couldn't expect any better.
please build spotify using only HTML and JS language features from 1996.
You obviously haven't tried Svelte yet. I would have agreed with you a few years ago though.
The churn as I've seen it has been a direct result of React's ecosystem, not in spite of it. Here's a partial list of React libraries that just provide state management:
MobX
Recoil
Redux
Akita
Context
Hookstate
Zustand
Jotai
Just for state management! And all exist solely because React state management is a monumental fustercluck.Then you get into React API nightmares the article mentioned that have nothing to do with HTML, CSS, and JS but have everything to do with React's API quagmire.
You may scoff at pointing to Svelte as "just a new shiny", but it really is getting back to the web's roots. Htmx as well. I've been doing web development professionally since 1996. I have hated web development since soon after React was introduced. React solved a lot of big problems to be sure, but it introduced its fair share as well as made web development tedious in a way I hadn't experienced before. I wasn't developing for the web anymore; I was developing for React. I constantly felt detached from my actual target. Wrapper after wrapper of familiar vanilla libraries to shoehorn into the React ecosystem rather than living alongside it.
Svelte (and Htmx to a lesser extent) gave me back plain ole HTML & CSS. Svelte also gave back that simple JS that described the problem I was trying to solve instead of endless boilerplate on an API layer on top of the browser API.
Vue got close but didn't go far enough. SolidJS just made a faster React. Svelte and Htmx embraced the web with no holding back, and I love them for it.
You provide listening points to various parts of your app, and when something changes, all points listening to that key also make the corresponding call to the server for refresh. It sounds hokey, but it's very effective, very efficient, and pretty easy to wrap your head around.
Htmx is quite popular among folks who prioritize and enjoy server-side development. Svelte is likely more popular among folks who enjoy browser-based development. There is certainly some overlap between the two camps, but that's my take on it.
The server side is only limited by what can run in a datacenter. Any language. Any service type. Any scaling profile.
Neither is more "correct". Both have pros and cons. As for why the backend engineer's point of view matters: if you are server-side rendering, you will have a better chance of going faster. A browser will always render HTML faster than JS that generates HTML on the fly, and the server side can always be made to generate HTML faster than a browser could. You can always simply throw more hardware on the server side to speed this up whereas you have basically no control over the performance profile of a random user's browser.
Look at Google search results. It's typically not JSON over AJAX; it's rendered HTML dropped into place. Why? Because every millisecond can be quantified into gained/lost revenue.
I think frontend state management is a completely legitimate choice if it fits your use case.
SolidJS stores work the same.
In other words, this is basically a solved problem unless you live in the React ecosystem.
That's 2013 or the year React came out and a full 5 years after the launch of Chrome/v8 started the next round of the framework wars.
On the frontend, things are even worse. Salaries started to skyrocket 7-8 years ago and the number of people suddenly interested has skyrocket every year for the past 5-6 years.
Part of the problem with this methodology is SO is useful among the most junior devs. For example, I haven't been to SO in several years but it was my go-to site in 2010.
This lack of experience carries with it the same flaws and risks (and occasional benefits) that inexperience carries everywhere.
quietly dries tears using pages ripped from ASP.NET For Dummies
After YEARS and THOUSANDS of projects proving that 2-way binding causes massive problems, the author insists I shouldn't believe my lying eyes. This may sucker devs with only a handful of years writing frontend code, but any dev who lived through those years won't be buying what is being sold.
"Hooks are outdated" is also false. I used Knockout and signals YEARS before React. Signals are NOT better. At a large scale, they are fragile and nearly impossible to debug because EVERYTHING in your entire app is a moving/mutating target. Just because they "aren't afraid" doesn't mean they aren't coding horrible bugs everywhere that will come home to roost from seemingly unrelated code changes in another part of the app.
The author claims that you can port libraries between other frameworks easily. This is absolutely false. The only "portable" solutions are going completely headless then making wrappers for various frameworks and if you do this, then React is no different than any other framework.
Bragging that you can't understand the difference between useMemo and useCallback after reading the docs (one is general memoization and the other is function-specific) isn't a dig at the framework so much as an indictment of the author.
Benchmarks are another interesting area. The actual delta between React and other systems isn't as massive as some seem to believe. More importantly, React's ability to defer rendering of some elements gives it the potential to feel faster to the user (which is the important metric).
I find the React is "hard to learn" claim fascinating. When I used AngularJS, it took 1-2 MONTHS to write basic stuff. Becoming an expert required 6 months to a year as you slowly learned the entire AngularJS codebase debugging stuff like the digest cycle. I taught a LOT of people to code React. 1-2 days to learn those basics and 1-2 weeks to know everything. The core React API has grown, but it's still not very complicated. Other frameworks may be quicker to learn, but in my experience, the difference is not huge upfront and there are almost always weird edge cases that haven't been documented that you'll run into (and that's without the signals edge cases).
Yeah, it is fairly obvious (though, to be fair, it wouldn't hurt to point it out) that:
useCallback((...args) => {
<*statements*>
}, [<*deplist*>] );
is effectively identical to: useMemo(() => (...args) => {
<*statements*>
}, [<*deplist*>]);Creating a first class hook whose only purpose is to wrap another first class hook, all so you can pass in a function rather than a function that returns a function.
About a year before hooks was introduced it was discovered by multiple teams that inline anonymous JSX functions could create big performance issues. This was particularly felt in react native development. The solution back then was to do the whole .bind(this) to your callback methods in your react classes.
Because of this (my guess) is the react team wanted to make it extremely obvious how you could use closure state as opposed to private method callbacks when they went intro hooks, without teams having to worry about taking a performance penalty with inline callbacks. It was not obvious to me (and I’m sure many others) when hooks came out that you could memoize functions before rendering.
Again, I get the redundancy point and maybe at this point it could be deprecated but I think you have to think about where the community was before hooks.
The two hooks have different names because they make different trade-offs.
[1] https://react.dev/reference/react/useMemo#memoizing-a-functi...
And we know it’s confusing because the React docs themselves reflect the confusion. A great example is useEffect, where the original docs quite clearly state that useEffect can be used to handle side effects, whereas the new docs say it’s used to “sync” components (and I don’t remember if it explicitly says not to use it for side effects, but that’s the common understanding people have now).
other way around. useEffect is for side effects (hence the name) and are _not_ needed for "syncing" state with props.
Right, the first argument to useMemo must be a function, but the first argument to useCallback need not. That's what you meant, right?
useMemo returns a value which is the result of calling the function it is given once the dependencies change.
So useCallback is basically useMemo called with a function that returns a function.
It returns something with the same type you gave it. If you give it a function it gives you a function back.
In typescript it's declared to take a function but in practice it doesn't check, and can be used to stabilize the identity of anything.
useMemo otoh _does_ only take functions.
If someone wants to invent a framework where two-way form binding is easy, but the data can’t leave the component without being dispatched as an action, I’m in.
(some will probably disagree, but I think most that have used Vue significantly won't)
- Two of the best developers I know are completely self-taught.
- I'd argue there have been so many front-end frameworks not for the sake of novelty because the web platform itself was incomplete and stagnated. (And also blew a huge opportunity with the APIs for web components.)
- Now that the platform is evolving and innovating again, more and more things are moving out of the frameworks and back into the platform. Javascript has massively improved.
- Some amazing and complex engineering happens in the frontend space because of the constraints and the need to eek performance out of everywhere you can. You can't just throw more servers at the problem.
- Experiences vary, but I've been on more projects delayed by over-engineering the backend than the frontend.
A language so good you need to write another language that compiles into that language to make it tolerable.
> Some amazing and complex engineering happens in the frontend space because of the constraints and the need to eek performance out of everywhere you can. You can't just throw more servers at the problem.
I'm not sure about this opinion. Most websites are slow as all get out and require me to download the world to even get working.
> Experiences vary, but I've been on more projects delayed by over-engineering the backend than the frontend.
As a person on the backend I can tell you your definition of "overengineering" is ignoring the fact we have to deal with frontend cowboys all the time. When SEVs happen it's us on trial almost universally. Just the absolutely bonkers states a frontend can accidentally end up in despite good testing is enough to warrant "overengineering" to try to support it.
We had an opportunity to kill javascript and instead we embraced it. We deserve what we get.
If static typing is your thing, I guess. It's not for everyone.
> We had an opportunity to kill javascript and instead we embraced it. We deserve what we get.
Some of us quite enjoy the language.
Some people need it to make it tolerable. That happens on every platform. You have Java and Kotlin/Scala/Groovy ... Microsoft even created F# to its C# ...
> We had an opportunity to kill javascript and instead we embraced it. We deserve what we get.
You mean VBScript? Or what other opportunity you mean?
I often get the sense that JS haters last saw the language in 1999. Modern JavaScript is a very nice scripting language. Succint, elegant, functional.
Its major omission is the lack of static typing, but JSDoc and WebStorm make it tolerable.
How? I really don't understand this sentiment.
The web components API is a gajillion times less complex to me than, for example, react.
Coupled with a light weight rendering library like lit-html, a basic component takes seconds.
- Make a class that inherits HTMLElement
- Create a rendering template in connectedCallback using your favorite templating/rendering library.
- Add class properties that call render() when they're changed.
The cognitive load is a fraction of what's needed for frameworks like angular or react.
And then you go on to list multiple complex things:
- Create a rendering template in connectedCallback using your favorite templating/rendering library.
So you need to bind together a connectedCallback and some rendering library
- Add class properties that call render() when they're changed.
So you have to manually wire class properties to manually call render.
In comparison, React alreayd handles all of that for you.
> The cognitive load is a fraction of what's needed for frameworks like angular or react.
Since you mentioned lit-html, that "lightweight rendering library" has all the "cognitive load" of React, and is getting more complex
It's no different than jsx, you just get to pick whatever you want. I honestly believe that 90% of the dislike for WC comes from the name "connectedCallback". If they'd named it "onCreate" or something, everyone would be using it. It's named that because it's the lifecycle method for when a component becomes connected to the DOM, so it's technically correct - a component can be created and function without being connected to the DOM. But people really hate that name for some reason.
It's all the same stuff. You have to do all the same things regardless of framework. You declare a template somewhere, you define the props that will cause a render on change, and you keep track of the internal state of the component. With React or angular or vue or whatever, you still have to do all this, you just incur the cost of a massive framework too.
> So you have to manually wire class properties to manually call render.
Yeah, 1 line of code. And in exchange you get to avoid a whole framework, get much better performance and have real control over your component's render cycle. Also, you still have to do this with react, it's just a different syntax.
> Since you mentioned lit-html, that "lightweight rendering library" has all the "cognitive load" of React, and is getting more complex
Huh? Lit-html is simpler than handlebars. Are you confusing it with LitElement?
I may run into "you're posting too fast, so not all part may appear at the same time" ))
Part 1.
> I honestly believe that 90% of the dislike for WC comes from the name "connectedCallback". If they'd named it "onCreate" or something, everyone would be using it
Of course not. None of the criticism towards Web Components ever mentions "connectedCallback", or how it should be named differently.
Do you know the actual reason so few are using them? Let's skip the atrocious not-really-high-level not-really-low-level imperative API that they offer.
How about:
- 13 years after introduction they still need 20 more specs to try and patch just some of the holes in their original design: https://w3c.github.io/webcomponents-cg/2022.html
- Shadow DOM is infecting every spec so that the actual useful specs like Scoped CSS have to be delayed almost indefinitely to try and figure out how to work with this abomination of a design
To quote the report linked above, "many of these pain points are directly related to Shadow DOM's encapsulation"
- The amount of specs that are required to make them work, barely, and be "good web citizens". And the amount of APIs.
Oh, you want your custom input to a) be able to send its data in a form, and b) be accessible to a label outside of your component? Well, there's a separate API for a) and there's some separate future API for b). And meanwhile your custom button won't be able to submit your form, sorry, it's a 4-year old issue with no solution: https://github.com/WICG/webcomponents/issues/814
And all that despite the fact that there are already a dozen specs covering web components, and dozens more on their way.
- Web Components ar HTMLElement. It means you cannot use them inside SVGs.
This is impossible:
<svg>
<x-axis min="2000" max="2019"/>
<y-axis min="0" max="100"/>
<scatter-plot points="..."/>
</svg>
This makes them unsuitable to a huge swath of graphics- and visualisation-related applications.- A smattering of other issues:
-- They cannot be easily used when progressive enhancement is required: SSR story is still non-existent, you can't easily update the original DOM in a custom element without trashing it.
-- They cannot be easily lazy-loaded because slotted content is eagerly loaded:
<p>Toggle the section for more info:</p>
<toggled-section>
<html-include src="./more-info.html"/>
</toggled-section>
`html-include` will load in its entirety even if you never toggle the section. And yes, this causes a cascading loading of multiple resources, too.-- they share a flat global namespace. Of course this will be solved in the next five years by a yet another spec.
--------------
If any userland framework had these many issues, it would be laughed out of the room. And yet here we are with people trying to argue that they are good now actually and all that stops them from being used is "connectedCallback" name.
These are also the reason why most framework authors that initially supported web components (Vue, Svelte, Solid) are now at best completely indifferent towards them.
In general, the points you're raising apply to edge case use of WC.
Most of your gripes are around shadow dom, and I understand that and agree with you - CSS parts and all that stuff are pretty bad. However - I don't use shadow dom. It was intended to be low level API for when you need to author with complete encapsulation.
I've been doing native WC for years and I've never run into a situation where I need shadow dom. Or slots. Or any of that stuff.
The "attributes" vs "props" thing is a html/dom issue, not a WC issue, and again - just about any rendering library will deal with it for you, the same way react or vue or whatever does. It's an utter non-issue in normal development, I write WCs every day and haven't even thought about that in forever.
SSR and lazy loading are anti-features for me. If you really want them with WC the sure, jump into a framework like stencil, but I have zero use for them.
SSR is all about SEO and FCP, and I've never really grokked it's usefulness.
If I need SEO I don't do UI SPA stuff, I just write server side, and I don't need a component framework for that. FCP (first contentful paint) is already a gazillion times faster with WC than any framework I've ever used. The whole point of lazy loading is to defer work until it needs to be done, but you already get that with reactivity - you trigger your component data load on a property setter anyway if it needs to load, and if it's just rendering off properties there's no need for a lazy load.
The TLDR is that you're making this massive straw man argument about bad API with WC, but it's for this tiny edge case of use that's only intended for library authors and such.
The 99% use case will never encounter any of that.
I could build up a big(er) wall of text about the same sort of stuff for all of the frameworks too.
When you want to do complex things - it's complex.
In years of WC work, light weight components using light DOM and a little templating library - I've run into the issues you're talking about exactly zero times.
Also, you may want to double check your understanding of frameworks use and embrace of WCs.
This is why I hate engaging into any arguments with proponents and apologists of web components.
Any concern and criticism is brushed away as non-existent and insignificant. Even if the actual people who develop this and push this into the browsers are now marking them as not only valid, but a significant problem.
But sure, do keep telling yourslef that theonly reason why more people don't use them is because people don't like the name "connectedCallback"
> you may want to double check your understanding of frameworks use and embrace of WCs.
Please do this yourself. Outside of frameworks and libraries that explicitly advertise themselves as being 100% based on web components (like lit and stencil) almost no one uses them as the foundation. They may consume them, and they may have a way to compile components to them, but almost none actually use them.
And yes, keep telling yourself it's because of "connectedCallback" naming.
I may run into "you're posting too fast, so not all part may appear at the same time" ))
Part 2.
> You have to do all the same things regardless of framework. You declare a template somewhere, you define the props that will cause a render on change, and you keep track of the internal state of the component.
> ...
> > So you have to manually wire class properties to manually call render. Yeah, 1 line of code.
So, there are two issues with these statements.
Main one is this:
So, for each property you need to track you need to manually call render. For each property in each component you write. Where in React, Vue etc. you... don't have to write that "1 line of code" at all.
And of course, "cause render on change" is trying to completely ignore the realities of re-rendering. If you "just call re-render", yo will run into a whole host of issues.
Example: You have a text box that has constraints on min and max number of characters. When constraints are validated, you want to re-render the input box with a red border. Well, the problem is: if you just re-render it, you will trash existing HTML, and replace it with new HTML, losing input focus.
And that's even before going into the fact that you want to minimize the amount of things you need to re-render. And "just re-rendering" trashes significant chunks of HTML.
That's why other frameworks (including lit) are not "just use template, track internal state and re-render". They track all the places where changes may happen, they keep track of user focus and input, many try and maintain scroll positions when large html changes happen.
---
The other issue is that it's not just properties, of course. It's also attributes.
Web components had a perfect opportunity to remove the distinction and only go with properties, but that opportunity is squandered. And the problem is: you can't reliably distinguish between the two. That is why libs and frameworks either give up and provide different syntax for setting them (like lit's `.property=` and `attribute=`) or rely on runtime heuristics.
And this is evident in the absolutely atrocious API surrounding attributes where you have to painstakingly manually sync attributes with properties in `attributeChangedCallback` with a bunch of `if name === "x" then`. Oh, and it's completely divorced from the `observedAttributes` callback because of course it is.
I may run into "you're posting too fast, so not all part may appear at the same time" ))
Part 3.
> Huh? Lit-html is simpler than handlebars. Are you confusing it with LitElement?
Of course not.
At the time of writing lit has:
1. A custom DSL for writing HTML
<some-tag
attribute=value
.property=value
?boolean_property=value
@event_listener=value></some-tag>
2. A custom JS DSL in the form of custom directives. Currently there are 12 of them.They may look like regular functions, but they will throw an error if you use them outside of their scope.
Example:
// is fine
html`<p class="${classMap({someClass: true})}">Hello, world</p>`
// Unhandled Promise Rejection: Error: `classMap()`
// can only be used in the `class` attribute
// and must be the only part in the attribute.
html`<p style="${classMap({someClass: true})}">Hello, world</p>`
(Note: that error is incorrect because you can write `class="other parts of the attribute ${classMap(...)}"`)More stuff is coming to lit, of course, such as contexts, server rendering etc.
Same feeling looking at the new Vercel SQL library. Oh wow now you can write SQL right next to your client-facing code, such convenient. You have just rediscovered PHP.
To be fair, frontend frameworks solve a problem. Application can get too big that you cannot manage all the states imperatively. Declarative UI building really help to keep the UI separated from the logic. But then management get greedy and and try to shove all the features they can think of into one single big app. Like, if you went to a page and click a button, going to another page will let you know that you clicked that button and shows up some nice CTA so you won't forget. Frontend people scramble around trying to create new abstraction to keep their working surface manageable. Then you get workflows where to get the result of an API call you have to dispatch a thunk action so it would update in the global store (my example may be antiquated, I'm away from React & Redux for a little while), instead of just, you know, call it and `.then()` update the UI.
Maybe if you have an app that is twice bigger than a normal app, maybe, I don't know, split it into two apps instead? The problem of web development app right now, I think, is because people are being monolithic where it should be independently modular, and then try to cut up your backend service into pieces when a single monolith works fine.
> PHP can't run in the browser.
Well actually, WordPress did it [^1] [^2]. They compiled PHP to WASM, so you can run our favorite web framework in your own browser.
I see your point anyway. Systems evolve. Tooling has to follow suit. PHP cannot achieve some of the feat today mega stack can. The problem arises when we apply the latest bleeding edge technology meant for systems that have to serve millions into our little MVP that may have less than 1000 users in your first few years.
[0]: https://vercel.com/storage/postgres [1]: https://developer.wordpress.org/playground/ [2]: https://github.com/WordPress/wordpress-playground
It was specifically the react/you-must-have-api crowd who bashed PHP bacause of this.
I guess in the end PHP was what people wanted all along.
What people wanted was the speed of a server-rendered starting point and the flexibility and performance of client-side templating and interactivity. JS/React can deliver this, PHP cannot.
OK, now you can do it using just one JS framework i guess? But is it a revolution? A breakthrough?
And this is parsed to one output file that is sent back to the browser.
You are either trolling me or you are not really sure how these things work?
JS was always here to stay. Wether you like it or not. Come with solutions instead of leaving it to someone else, or worse complaining.
JS was always super exciting, with a few lines you could build entire applications.
Can you talk more about this one? I think this is getting at something I've seen but have been unable to articulate thus far.
I thought we, as in the community, learned a while ago that was a bad path to go down.
That's why there's a resurgence of old-school (yeah, I know...) frameworks like Rails. Or why things like Laravel and the PHP world keep thriving.
Well, React is old now. We know. It's the Rails of the JS world. And it's plenty good enough.
If you know JS/TS and are comfy in that, just use React. Don't feel bad for not using whatever shiny new thing is trendy now. Who cares.
No one ever got fired for choosing react, as some other commenter said.
If I’ve learned anything in my twenty years programming, it’s that the development community never learns anything for more than about twenty minutes. There’s too much turnover without a great mechanism for handing down folklore and war stories.
I’ve been think about this a lot. Like how htmlx is reinventing something called pjax (though better). There’s many other examples. It’s a lot of newer programmers never investigating the “lore”. I don’t think it’s part of CS curriculum, and boot camps certainly don’t teach it. Forget how things they are using works. It’s woefully common for js devs to not understand how variable referencing works. (Which is super important for reactivity)
I’m all for not moving from one hot tech of the day to the next hot tech of the days.
But let’s not stop on react.
> If you know JS/TS and are comfy in that
…there are better options than react.
> No one ever got fired for choosing react, as some other commenter said.
The the extent that’s true, I think it’s only in the sense that choosing react is more like a symptom of the shortcomings that get people fired.
Anyway, it’s the same urge to follow the heard that made react popular in the first place that will lead to its decline. New shiny things are calling. I hope we collectively choose better this time.
Well, the current top commenter says:
> I lost my last job because of it and all associated technical debt.
But I don't think a tool should be blamed there :)
But as someone that just learned (learns) react, the useThis and useThat stuff is confusing and lots of details to know how to write it so it doesn't do useless re-renders. It takes time to read and practice all of that.
That's supposed to be a pejorative, to describe how what management wants is rarely correlated with what's good or useful. 'Ignore shiny stuff' is the rallying cry when the shiny stuff is less performant and harder to use; as TFA illustrates, the thing about React is everything is more performant and easier to use than it. Where is the value in using React instead of Svelte for new development? If it is just that you already know it, what do you think of TFA's assertions about learnability?
The difference between React and Rails is, well, pretty much every mentioned negative attribute of React - Rails neither is terrible for performance, nor is full of hidden pitfalls, nor requires lots of boilerplate for simple actions, nor is incompatible with most Ruby libraries, etc.
I really think 'new stuff bad' rhetoric here is being divorced from every real reason usually backing it. 'React is good enough' is like someone saying 'MongoDB is good enough' - no it isn't, it was a huge step in the wrong direction and everything invented since it is moving towards more streamlined versions of the old ways of doing things. You explicitly reference the resurgence of old-school stuff, without noticing that it the thing it is specifically a rejection of is React.
You cannot be serious. Every single one of these points is a criticism I've seen leveled at Rails (in many cases on this very website) at some point or another. Performance? People wouldn't shut up about how slow it was compared to traditional server-side languages/runtimes which could do multithreading, or (later on) event-loop-driven runtimes like Node.JS. Hidden pitfalls? I'd like you to meet my friend, Mr. N-Plus-One Query. Boilerplate? I suppose this is a fair point, but on the other hand there were tons of people complaining that there wasn't enough boilerplate- that it was too magical. And incompatibility? Can I point out the libraries that weren't just written specifically to be used within Rails, but actually depended on its heavily-customized initialization and environment preparation?
? There has never not been multithreading. And yes, people said it was slow, and they were wrong at the time, having confused single-threaded performance with scalability.
> I'd like you to meet my friend, Mr. N-Plus-One Query
This is a general problem in all ORMs, it's got nothing to do with Rails and the closest anyone has ever come to solving it is LINQ, which still isn't very close.
> Can I point out the libraries that weren't just written specifically to be used within Rails, but actually depended on its heavily-customized initialization and environment preparation?
You can, but it doesn't really have anything to do with the point: there are Rails libraries that don't work outside Rails, but Rails is not incompatible with wide swathes of non-Rails libraries. The problem with React is not the quantity of React-only packages, it is that many non-explicitly-React-only packages don't work.
I’ve also been hearing the same critique against Go basically since it came out. Meanwhile, the companies I’ve worked at continue to ship with these antiquated technologies and I’ve never once felt that those language or framework choices measurable slowed things down or otherwise hurt the team. Other factors (poor requirements, bad system design, bad management decisions) dominate the causes there. I’ve come around to the lackadaisical option that so long as the tech is compatible with the platform you target, and you can hire people to use it, it doesn’t much matter what is picked.
I'm not going to migrate outside of React unless I were to get something out of it. I did not see anything someone would get from switching. I don't understand why people write these kinds of blog posts when they're so non-persuasive.
That is what I got out of it.
I always wonder if the authors of articles like these have an equivalent (or even adequate) amount of experience with all the many frameworks reviewed in the article. It's really hard to judge what they're good at if you haven't done at least a good-sized project with each one, and it's hard to imagine having occasion to do that. You definitely can't base it on what the framework homepage claims, or its own example projects.
I don't do front end development for money anymore, but when I did I always defended React against its critics. Then, when I stopped having to use it every day, I immediately realized I never wanted to touch it ever again. My defense of it was probably just Stockholm syndrome, looking back.
Let's take a look at the frameworks available for this...
Gatsby > 50K stars Next.js > 110K stars (!) Remix > 24K stars (impressive, only 2 years old!)
and looks like Svelte has... ultimately... Sveltekit. Svelte has Sveltkit:
Sveltekit > 15K stars
React is great; not because of React itself but the massive ecosystem and number of frameworks behind it. There isn't a component or hook under the sun you can't find.
I grow weary of such posts, still waiting for an objective truth as to what really differentiates a frontend framework and makes it so much better than all others; still haven't seen it.
I get reactivity with class properties and a call to render().
It's so damned easy and straightforward, super fast light weight little components that know how to take care of themselves.
I stick with the light DOM and use a CSS design system that matches the project - bootstrap or whatever.
I have zero build time during development, and a quick "vite build" for deployment - just for easy packaging.
No framework churn.
No complex debugging. What you code is what you debug in chrome dev tools. No source maps.
No complicated state management or insanity like redux.
A new dev can be set up and productive in a day or two, and that includes learning how Web Components work.
I've been sitting in my lonely corner looking at the room full of unbelievably complex front end frameworks and scratching my head.
I just don't get it.
I’ve recently been doing a lot of react work. Even relatively simple changes on pages that are just pretty basic forms that probably shouldn’t have ever been a react page in the first place are huge changes. Even ignoring updates to the backend, adding a basic fields to a form with some validation can be 20+ files changed.
This week I updated a rails Erb file with jquery, wow it took 1/10th the time, file changes and energy. Really the golden age of web technology.
React probably has a place if you’re making a single page application at the scale of Facebook, but otherwise I don’t see it.
That sounds a lot more like a problem with the project you're working on, than a React problem.
So I naturally assumed that Angular was slower than React, but turns out it is not the case any more: https://krausest.github.io/js-framework-benchmark/2023/table.... (click on the "Which Frameworks" dropdown to filter on Angular + React)
I use Angular a lot in my day job. The learning curve is steep due to RxJS, but otherwise feels fairly sane as everything is included.
The article states that there are better options now so continuing to use React is not the best choice. This was predicted by most advocates of React fairly early on. The mantra was always: React will be replaced by something better; for the time being that something is still React (i.e. present day React looks very different from the early class-based React).
At the time React started gaining momentum it was simply the best option for what it did. The biggest alternatives were AngularJS (which was known to be a dead end), Angular 2 (which was stuck in Google's cycle of "let's rewrite everything several times because we're not dogfooding this" -- remember that Angular 2 was initially based on `Object.observe`) or the old rusty toolbelt of jQuery, Backbone, Knockout and whatever else was still polluting globals at the time. React eliminated entire categories of bugs at the time and was the first major frontend framework (well, library) to also support server-side rendering.
I think good arguments can be made that e.g. lit-html or htmx is superior to JSX. But at the time those didn't exist and the reason people disliked JSX was that it was different and that it looked like something many had tried before (i.e. VDOMs and XML-ish template DSLs) and that had always ended up sucking. That criticism however came from a place of ignorance (literally "not understanding how it actually works and what it is") and prejudice (i.e. judging by superficial first impressions, not the actual implementation and semantics).
If you think React has uniquely done "so much damage", you either think frontend frameworks in general are inherently bad (which is an entirely valid opinion to have tho I wonder why you think seeking out articles about things you hate just to vent about them is a productive use of anyone's time) or you're being extremely disingenuous with regard to what came before React and what can be considered "React's fault".
Where are my AI JS blog post generators at?
Unless … No can’t be … There’s no way these articles have been AI generated this whole time … right? RIGHT?
True. On the other hand people are now rapidly waking up to the fact that the promised simplicity of having real module systems running in the browser (and ideally federated at that) introduces a ton of complexity (not to mention performance problems) compared to simply having a bundler even when you have to deal with code splitting.
It's also easy to miss how rapidly React influenced the space. Because React was so narrowly defined (i.e. it didn't bring any state management or styling - I remember it being called "just the V in MVC") a ton of other libraries sprung up around it and it even led to a short rise in popularity of otherwise very niche reactive functional programming DSLs and arguably helped sparking interest in reactive programming in general, such as RxJS (which has since seen and ebb and flow of popularity in Angular).
And in order to get the “convenience” upgrade over jQuery+backbone or whatever, you had to abandon all existing standards and best practices, making any JavaScript you were using that was not in the style of React useless.
Web components that encapsulate state and interactivity, usable alongside a regular HTML page, were an emerging direction when React shipped and forced everyone to re-write ‘class=‘ to ‘className=‘. And being forced to re-write every app as an SPA was a dumb idea the day people started doing it, even in light of other available approaches.
You’re right that a lot of people hated React before they ever tried it, and they were right, even with the full knowledge of what it was replacing.
They weren't. By 2013 web components were still flailing around completely ignoring everyting that was happening in the world and coming up with an unusable and badly design API while crippling a bunch of other things in the process (like forcing C++-like OOP onto prototype-based Javascript)
> when React shipped and forced everyone to re-write ‘class=‘ to ‘className=‘.
React is basically just Javascript. What do you think className is? https://developer.mozilla.org/en-US/docs/Web/API/Element/cla...
> And being forced to re-write every app as an SPA was a dumb idea the day people started doing it, even in light of other available approaches.
What do you think web components are if not a way for people to dump a bunch of Javascript onto a page (and dozens of Javascript-only specs to accompany them)?
You can get most of what you need onto a web page with HTML. Some components need to be interactive. For that, you need JavaScript. The question is, do you:
1. Keep the rest of the HTML in place, and add JavaScript to that HTML for the interactivity you need (the web components approach)
Or,
2. Re-write the entire web page as a JavaScript “app”, including the parts that are just fine as static HTML, for the “convenience” of the pieces that need interactivity (the React approach)
Both involve “dumping JavaScript onto a page,” sure, but they are totally different approaches.
For a decade, the entire industry picked “2”, and now the internet is a bloated disaster.
It's not the web components approach. Almost nothing about web components is about progressive enhancement.
> Re-write the entire web page as a JavaScript “app”, including the parts that are just fine as static HTML
That is literally what web components are. They can't even participate in forms without Javascript
Heck, even literal Web Components were stuck in that direction. The big reveal of the Web Components implementation in Polymer involved a demo page that was literally an empty HTML page with a single <DemoApp /> custom element node and a massive JS runtime. And that was after React had become popular enough for Googlers to actively heckle React and other libraries on Twitter: #UseThePlatform.
React of course lapsed in server-side rendering eventually because it was not a priority to Facebook and therefore only an afterthought. Arguably the killing blow was Create React App not giving any thought to it at all. But one of the most popular React frameworks is Next, which is now more than 6 years old and is best known for being good at SSR.
The class vs className thing is a silly argument and enough articles have been writing about this that I don't need to reiterate the full argument here but basically the DOM API calls it className (because it wanted to avoid reserved keywords in property names) and most libraries have special-cased "class" to be an alias for "className" or even go out of their way to prevent you from using the actual property name. React actually does less here, not more. The rendered DOM itself (i.e. the HTML sent over the wire in SSR or what you see in your DOM explorer) is no different whether you use JSX where it's called className or a template language that translates "class" to "className" for you.
My sense is that there won't be another leap in the conventional sense of a new dominant frontend paradigm that will be so "optimal" that it can be all things to all people. jquery was at some point used like for 98% of websites. This historical precedent created the false expectation that the web is a single something. But this is no longer true true. The arrangement of browser/clients - servers is so flexible that very many patterns are desirable and viable even though not yet fully crystallized.
More likely the next "web" will bifurcate (or maybe trifurcate). Its not yet obvious what the different web "subtypes" will look like. There is now a visible revisiting of paths not followed during the breathless SPA years (e.g. minimalistic reactive frontends (htmx, alpine.js) in combination with popular backends (phoenix, laravel, django). There are also new horizons with wasm (e.g. running the entire python data science stack in the browser). And worth remembering that knowledge management challenges that were once thought resolvable through the "semantic web" are basically still unsolved. At some point an LLM will scaffold an SPA/CRUD/sort-of-REST thingy in its entirety and we will need to move on to some truly unsolved problems.
Thus, a lot of this heated debate and people talking past each other is, imho, just a waste of time and it won't be relevant in the big scheme of things.
> We shouldn’t need to do that—especially for a framework that so often claims it’s “just JavaScript.” If it’s just JavaScript, then it should just work with anything that’s actually just JavaScript.
And this:
> I have a confession to make: I’m still not exactly sure what the difference between useMemo and useCallback is—or when you should and shouldn’t use them—even though I literally read multiple articles on that exact topic earlier today. (No joke.) > > I have a second confession: it’s still not intuitive to me what should and shouldn’t go into the useEffect dependency array, or why. I feel like every time I write a useEffect call, I spend like 15 minutes refactoring my code to be in a shape the linter likes, even when I’m 99% certain it’s actually fine and it’s not going to suck my app into an infinite abyss.
It’s not just “not new” it’s considered to be actively worse than all of its peers in terms of things like performance and complexity, it’s actively a very questionable choice in a greenfield project in 2023.
Goes back to writing SQL
When I’m developing an application, I could not care less about what tech it’s built on. I’d much rather just pick something old and familiar that’s stable, has a huge ecosystem, and has tons of common issues answered on places like stack overflow.
These flavor of the week types of posts are always worth a read because it’s possible that something else may supersede react eventually. But proper understanding of the render cycle plus use of the react debugging profiler has been enough in the apps I’ve worked on to make them lightning fast.
Oh and typescript is a mistake.
In general dont start your web app as a SPA.
Probably (99% of cases) your web app does not need to be fully SPA. If you need live data/reactivity sprinkle part of SSR pages with whatever FE framework you feel is good.
HTML and Vanilla JS are very maintainable over long term. So is being able to share a web URL and see the exact information without doing anything extra to make it work.
Try to resist the urge to use a fancy framework as much as possible. JS + HTML will go a long way.
Push back to designers asking you to do things that needs you to architect a full SPA. Most of the times the users dont want that. Ask what is the actual need that should be solved.
As we are on this subject: please dont start with infinite scrolling. It adds do many case to be handled.
My RSS reader YOShInOn is mainly SSR with some HTMX and little dollops of “plain ordinary Javascript”. For instance there is a test file that only takes 80 characters and there is just an event handler that counts the characters in the field and changes the UI accordingly. Granted there is the complexity of “first render” vs “update render” and I’m addressing that with rendering the count and disabled button status in the SSR and the event handler but the event handler could do the same work in the onload handler if necessary.
It’s how to do stuff with plain ordinary Javascript that’s been forgotten.
I am creating a project using React + Vite which could have very well been created in vanilla JS, but just to get familiar with React and also to show some proof to prospective employers. So just wanted some advice on whether React is the way to go, or is Vue/Svelte where the industry is heading towards? Also any other tips on what you would be looking for when hiring a dev would be very helpful. Thanks.
You can write interfaces on the server, wrap them in HTML documents and send them to the user performing SERVER-SIDE rendering. But not any of this directly entitles React.js as a web framework, and it is utterly incorrect to start comparing it perpetually with what it was compared to.
React was a true revolution in the functional user interface development area. The concept of side-effects, hooks, and reactive renderer comes from the functional paradigm which is not so easy to grasp. This fact alone makes all these articles to come.
The author is true to his "it’s still not intuitive to me what" and "I’m still not exactly sure what the difference between" lines throughout the whole article, but with great confidence he compares React with jQuery and Vue. I would say it is still not intuitive to him what is React in its core, and how different it is from the web frameworks he is trying to compare it to.
React is a functional Javascript library to craft anything related to User Interface. It is incorrect to label it a Web framework exclusively and keep comparing it with others because there are 10 different frameworks based on React, but just a single React there are.
And the React is much more of a bundle of functional concepts than a full-fledged framework for doing anything. You can easily shoot yourself in the foot if you take it wrongly, as it doesn't provide you with clear instructions for making things work. It leaves you on your own with hooks until you understand 6 of them are all you need to create the interface in it's gorgeous simplicity. At some point, you understand that if your hooks are complicated and you cannot grasp your effects - then it is your interface that is complicated and your thoughts themselves went astray to entangle this monster.
The moral of the story is, what ever cool now changes fast, and it shouldn't matter. Do what you love and don't preach because not like any genre of music, crusades are not cool for like 1000 years now.
React is still a good tool for writing MPAs, if you can get your team to stick to it. But unfortunately, if you aren't careful, React has become an infectious disease and slowly eats your whole frontend, even where it's not necessary and in fact, counterproductive. Pages which initially had a component or two, slowly are completely rendered in React, and when this happens to enough pages, someone starts wondering why your site isn't an SPA. It's hard to steer teams away from this, because the short-term benefits always seem tantalizing, and few people stay at jobs long enough these days to grok the long-term downsides.
I've started to think having a JS build step (beyond bundling/minification) at all is the original sin here, and lately I've been doing a lot of my work with just vanilla JS and web components. Web components have their downsides which I've criticized elsewhere, but at least they aren't all-consuming. I've also been playing around with a few lightweight frameworks which don't require a build step like alpine.js and lit.js, but haven't committed to one for a production project yet. The biggest downside to this is that there aren't good tools for automated testing without a build step (that I know of! If you have some please mention them).
This started happening to me this year. And all the other senior devs who know better happen to be gone from this project, so I'm alone having to convince these junior engineers (working on a very large non-JS-backend web application mostly with content pages!) that SPAs are not the ultimate solution to all. It's so frustrating.
"there aren't good tools for automated testing without a build step"
For our vanilla JS we use browser-based tests which we can check in any browser anywhere any time, and which can also be automated and measured with a headless browser from the command line. And we have also used Node and had even more luck with Deno for testing individual functions and libraries which may get used on the frontend! Hope that helps!That's a business decision, and not a given
Of course there are exceptions. But it's definitely a hot take to say you should never prioritize DX over UX.
If your business competitors prioritise UX over DX, your users will soon know. And then they won't be your users any more.
All those are important, and given a talented team, there is absolutely no reason why you cannot have good UX, lots of features, few bugs shipped on time.
Maybe you are mixing up the UI design with the UX? In any case, the original point is just highlighting the importance of UX, without giving any solid examples of DX.
See usage of React Native for example, it certainly produces apps worse than native ones, however many businesses still choose to work with it because you can improve the developer experience and ship faster.
I've worked in quite a few companies that were always pushing to ship faster and we're okay with the trade offs in missing tests and worse UX. The talk was always that we'd ship fast now so we can step back and clean up later but that's extremely rare in my experience.
And all of them are available to you if you use React, too.
I stopped reading after a while becauze this post shows complete ignorance that React is not a framework. It's just a tiny general lib focused on rendering things reactively. It doesn't care if it's used in web or not. The core package doesn't even know about DOM unlike eg. Preact that is specifically limited to web.
PS. If you are so knowledgeable about frontend, it's even more glaring that your website hijacks scrolling. Why?
const useCallback = (fn, deps) => useMemo(() => fn, deps);
That's it. That's all it is. `useCallback` is a shorthand for `useMemo`, when you want to memo a function definition.Example:
const handleButtonClick = useCallback((event) => {
event.preventDefault();
window.alert(`Hello, ${name}!`)
}, [name])
is just shorthand for const handleButtonClick = useMemo(() => (event) => {
event.preventDefault();
window.alert(`Hello, ${name}!`)
}, [name])useCallback is for callbacks, useMemo is for memoized data.
<ul> <li v-for="todo in todos" :key="todo.id"> {{ todo.text }} </li> </ul>
Many developer miss type a `todo.text` as `todo.test`. React detect error in compile-time. That is enough to reason of selection. And React slower than Vue, Svelte, but Next.js is faster than other framework many situation.
For small teams frameworks like react & others are (sometimes, not always) overbloated and overkill.
If you want to use finished components without reinventing the wheel, you stay better sometimes with big frameworks like react or vue, ... with all pros and cons.
Sure, it would be nice to use components and tools, that are not framework agnostic, but these are rare or you have to use many, that is a problem for huge teams (fragmentation).
I've worked on a rewrite of an old AngularJS and it felt like such a waste of time. It didn't matter what the new target of the rewrite was, the fact that we had to was very painful.
So, who cares about that "Web component is awesome" ?
Just use React and grab the money.
React "simulated the DOM" into minimal surface API for busy devs to use and be productive. That's the whole point.
Seriously, i don't trust the DOM at all. They're not 1 standard, they behave differently on different browsers.
React is 1 standard to me.
but for a large project still react.
Do you have any recommended learning resources on building with Lit?
Privately, I always go with vanilajs.
The book is a really quick and easy read. It’s pretty eye opening how productive, and effective, htmx can be with so little magic.
i set up routing with the views available and i write a class for each view. there is practically no boilderplate code. (eg what is $scope in angular is simply the class object itself in aurelia)
any class level function and variable is automatically made accessible from the html template. classes and templates are linked by sharing the same name: welcome.html, welcome.js, export class Welcome ...
while in angular you have to declare everything explicitly, aurelia mostly just figures it out by itself.
If you do have a backend framework, then having the backend drive the dynamic updating is a pretty great way to go, so HTMX[1] is the least obtuse way of putting the most power in the hands of the backend. Really makes 'a light sprinkling of JS for interactivity' closer to reality than vanilla JS allows, without adding cognitive overhead.
[0]: https://svelte.dev/ [1]: https://htmx.org/
I recall seeing far more negative sentiment than positive over the years re. hooks. Maybe it's just me.
When using a sharp knife it's even more important to stick to the principle that slow is steady and steady is fast. It's the same thing with react, and really any of these frontend frameworks that keep piling on complexity. Sure you can ship features fast and if it's throwaway code the great, but if you ever want to reuse or grow it that quick code is a nightmare of tech debt.
The whole things about "rules of hooks" should tip people off that it's sketchy. I mean, have you ever actually thought about how:
function Component() {
const [state, setState] = useState(1);
return <>{state}</>
}
actually works? How does `useState` know what bit of state to grab? (it's a global store identified by the function you're in, and an index. it's why you can't change the order of hooks nor call them conditionally).Hooks are literally javascript in the sense that they're functions you can call in javascript, but they don't operate under any of the rules people actually think of when they write javascript. If for any `function x() {}`, `if (condition) { x() }` was a fatal error, people would consider that terrible API design and the function shouldn't need to care whether it's called conditionally.
Sure, react hooks 'compose' better than class components, but they also don't compose *at all* with anyones mental model of how JS works. What they needed was different syntax or a DSL in general (what svelte does is a lot more understandable, imo).
[0]: jsx is a DSL but it's merely one bit of syntax sugar. they needed a hell of a lot more.
useEffect in particular really messes up my understanding of the flow. Lots of bits of code that may or may not be executed based on the dependency array, and that means my component function is going to be executed several times, each time just to execute another useEffect. It works, but it's not a programming model I like.
> that means my component function is going to be executed several times
Who cares? That shouldn't be your concern. All you should think is "this effect will get called every time these values change. Am I okay with that?" React will handle running your component function consistently with the right state, you just have to worry about whether your component is rendering the right thing given that state, and running the right effects. React handles correctness. You don't have to remember "oh whenever I update this state, I have to run this other function to make sure everything is in sync" as with class-based components. Because invariably, another engineer will come along, make some changes, and forget to call that function. Now you have a really tricky bug to find that depends on internal state.
This is why hooks have caught on: you can truly write pure declarative components (most of the time) and not worry about execution order or dependencies at all. The tradeoff is that you have to think very...reactively. It's definitely a different mindset, but it means that there's a whole class of bugs you never have to think about because React handles it.
Have to agree here, game-changer when they came out but now every repo I touch has 100 custom hooks. Junior devs don't even understand why they're called "hooks".
Compare the old docs about useEffect() to the new, it's widely abused.
the article says:
> In my opinion, most projects still benefit from using a frontend framework over pure web components—or, at the very least, both together. Maybe that will change in the future, but for now, I think the tradeoffs still tilt away from a pure web component approach in most cases.
but doesn't provide any real argument to justify that opinion.
why would anyone want to subject themselves to framework lock-in when you can have components that are portable across frameworks? what are the arguments against?
genuine question -- i've used Vue and i've used Lit, and didn't see obvious limitations in the latter, but i've also never used either for any large project.
https://twitter.com/Rich_Harris/status/1198332398561353728
None of these are solved, or will be adequately solved in a forseeable future.
Some of these will be addressed by ~20 new JS-only specs in the various states of "not started" https://w3c.github.io/webcomponents-cg/2022.html
Literally none of the major (or even emergent) frameworks have these issues, or a chance of running into these issues.
#2: maybe i'm misunderstanding, but i think frameworks can implement SSR on top of vanilla components, for instance in Lit: https://lit.dev/docs/ssr/overview/
Lit solution also lists a lot of caveats including things like "only Lit elements using Shadow DOM can be SSR'ed" and "element registry needs to be solve for interop with other custom elements" (that is, there's an issue on the standards level)
Because, admittedly I only have a view of react of having used it to enhance a server rendered (PHP/twig) page with rich interactions (Making a UI widget/gizmo that lets the user manipulate the data easily before form submission etc).
On the one "full app" that's an offline React PWA, our only real pain point has been the report section, because the report structure is dynamic (controlled by a config from the server) and recursive which made ensuring the correct components are shown and having performant state management challenging.
Of all the new ideas, I'm most excited about Electric Clojure. The ability to strongly compose across frontend and backend feels very powerful.
Hi - year 2000 calling...
"Learning a framework" doesn't mean creating a todo app over a week or two. It takes years to really know one. I don't have that time or energy.
In the thick of substantial engineering projects, when all your initial plans and architecture have not survived contact with the enemy [1], you realize that any robust, maintainable, really successful piece of software only gets that way by going against the zeitgeist of frameworks, patterns, tools, and architectures. Not only must you use boring tech, you must do some thing directly contrary to "best practice".
There are many examples to support my point: CloudFlare's "weird" internal architecture which is heavily DB-based (making heavy use of stored programs and the like) [0], to Google's use of all kinds of internal innovations: Protobuf, MapReduce, Closure compiler, etc., and more I can't think of now. It's a testament to the somewhat sad state of software as an engineering discipline that so much of our real world engineering has to go against state of the art.
For example, just the other day I came to the conclusion that all JS bundlers are "bad", unable to meet my need to reliability, efficiency, and speed. And my needs are not even at the edge. So, I am not exploring crafting complex front-ends without bundlers at all. The shiny things that are constantly being pumped are not subject to, or the result of, a long period of real world use. The examples used to illustrate most are toy examples with virtually no relationship to what the experience of using them in a substantial project would be.
And, yes, I kind of hate how React has taken over everything, although I like JSX, the idea of UI as a function of state, etc. So I had to write my own UI library to get away from React the library, while still being able to write UIs in a react-like way. I hate other heavy UI frameworks even more.
The way forward is to get back to basics. Learn from various libraries and frameworks, but do not import a million dependencies into your project, and do not depend on too many tools. I believe each piece of software must be crafted almost from scratch [2], embedding modern but tested architectural approaches, in an almost monolithic way.
[0] https://news.ycombinator.com/item?id=22883548
[1] The enemy here include complexity, performance issues, shifting requirements, time and cost estimation, and similar things that bedevil substantial software projects.
[2] Not totally from scratch, otherwise you would have to boostrap an OS, compiler, and stuff. But the black boxes you rely should be _very_ robust, and easy to reason about. No one gets confused about, or has to debug, what is happening when they save a file. You trust what the OS is doing , although it can be quite complex behind the scenes.
In a more middle case, it's just people explaining what they did when they faced a particular problem, and how well their solutions worked. There's a cynical version of this too, where people are more focused on their employer-brand or personal-brand than being helpful.
Not to downplay the actually helpful instances of thought leadership! I'm just observing that there isn't always an easy way to tell these things apart, or to boost the helpful ones.
When I’m being excluded from job descriptions because I have react on my resume I’ll revisit this article
It wasn't.
- phoenix liveview / ts-liveview / hotwire
- htmx
- clojure
- cycle.js
- dom-proxy
- data-template
React creates layer upon layer of unnecessary, opaque abstractions which make it harder to debug complex front ends and it encourages poor engineering practices. For example, I've seen a lot of cases of junior developers dump setInterval() calls all over the place into the code inside useEffect and not cleaning up afterwards... Causing memory leaks. But these devs can work so fast using React (to get features out in production quickly) that managers just love them and it's difficult to convey to them that this is in fact a short-term approach and it will come back to bite them in the long term. The app at that startup had such awful memory leaks that my new computer would freeze a few times a day.
I feel like the new generation of devs got used to working with these abstractions and by some measures they seem highly competent, yet it feels like they're missing some critical knowledge; like they don't understand what's happening under the hood. Sad because there's actually a lot less happening under the hood than there is happening above it! You can solve many problems while staying closer to native browser features without all this complexity.
Have you been exploring any other technologies since React?
So far it looks like I won't even need to go there... It turns out it's pretty easy to manage a web-component's dynamic state without reactivity (at least based on how I architect my apps). I find the HTMLElement lifecycle hooks (and attributeChangedCallback) to be sufficient.
React got popular because at the time, Angular.js was the framework of choice and we can all agree Angular had some serious problems like the digest cycle and performance issues working with large collections. React in comparison to Angular was a breath of fresh air, but in 2023 there are far better choices now than React.
The thing is, React started out as just a view library and the community are mostly to blame for how terrible it has become. How many state management libraries have there been? How many router packages? Devs think they want a library, they actually want a framework. It's why the most popular uses of React are not vanilla React, they're frameworks like Next.js. Also, when you compare the performance of React to other libraries and frameworks, you realise it's one of the worse performing options. It's slow. The whole entire notion of Virtual DOM was groundbreaking in 2013, but in 2023, reactive binding approaches like those taken in Aurelia and Svelte are far superior and better performing. Virtual DOM is overhead.
Has anyone ever seen a large-scale React project that is just using vanilla React? I've seen a few large-scale React codebases and many of them were a tangled spaghetti mess. It gets to a point where React's lack of opinions and standards for even the most basic of things mean you can see the same thing implemented 100 times in the React community. If you're building something beyond a landing page or basic CRUD app, you need some conventions. There is a reason despite the hate it gets, Angular is still used in enterprise and government settings. It's verbose, but you write components and other facets of your apps a specific way and know that Developer A implementing a feature is going to be understood by Developer B because it's not going to be so self-opinionated. This is something that backend frameworks learned years ago.
Don't get me started on the terrible communication from the React team. A good example is how they have handled React Server Components. They changed the docs to recommend RSC's by default, despite the fact many community packages don't work with them or require additional packages. The way they approached RSC's and rushed them out was terrible. This isn't the first time either.
I have been working with Aurelia 2 (https://docs.aurelia.io) and I love it. It's intuitive, it's fast, the developer experience is great, it comes with all of the needed dependendencies you need like a router, validation, localisation and whatnot. No need to go building a faux-framework of Node packages bloating your app. I've also been working with Web Components, which are in a really good place now too and getting better with each proposal (there are a few good WC proposals in the works right now).
Developers need to start using the platform more. Web Components have been supported by all browsers since 2020 (Chrome has supported them since 2013), so it's a good time to dive in. Using something like Lit gives you a nice development experience. Part of the problem is React developers have been brainwashed into thinking classes are bad because of some terrible design decisions in React (which led to Hooks) and writing Web Components relies on using class syntax (although, you can write them as functions if you really want to).
React is anti-standards, it's anti-developer and it's bad for the platform. The fact that React is ten years old and doesn't support Web Components still, goes to show just how little the React team cares about Web Standards . I know jQuery is a bit of a meme now, but at least jQuery helped shape modern standards. Has anything good come from React for the platform?
- Arrays are observed by monkey-patching the push, pop, and other methods. There is no concept of assigning keys to cells [1]. So, if you want lists to be stable, you must manually diff the arrays and mutate the old one.
- In general, the observation system was awful. They have a custom JS subset interpreter for their templates, and they secretly add properties to observed objects. If all else fails, they will start up a 300ms timer that polls for changes.
- The binding system favors mutations over functional updates, but deep-observing objects isn't possible. So, if you want to observe a data structure for changes, you may need to write down each key.
- I encountered multiple bugs in the templating language. I don't remember the exact details, but they were similar to this: If you have a containerless element somewhere inside a conditional element, that's somewhere inside a repeated element, the containerless element isn't rendered.
- No type safety in their templates.
- No conditional slots, no dynamic slots, it's not possible to forward slots, can't detect if a slot is used.
- In my tests, performance was worse than React.
[1]: Unless you dig through GitHub issues and find an external contribution. However, it was broken for some time and doesn't follow the Aurelia conventions.
- There is no dirty-checking in Aurelia 2. The observation system now uses proxies and other sensible fall-back strategies. The computed decorator for getters is also gone in v2, meaning no accidental vectors for dirty-checking.
- Observation system was rebuilt to use many of the same strategies detailed in point one. No dirty checking and proxy-first. Similarly, your next point about mutations, also has been addressed by the new binding system.
- Many of the templating bugs people encountered were spec implementation issues due to how the browser interprets template tags and content inside them. There were a few repeater bugs, but the ones outside of non-spec compliance haven't been a problem in years and do not exist in Aurelia 2.
- You can write type-safe templates now.
- You have have conditional slots now if you use the new au-slot element. A lot of the slot limitations in Aurelia 1 were because Aurelia adhered to the Web Components spec for how slots worked. In v2 there is still slot, but a new au-slot has been introduced to allow you to do dynamic slots, spot replacement, detect if slots are defined or contain content.
It's important to realise Aurelia 1 was released in 2015, so it's not perfect and some design decisions reflected the state of the web and browser limitations at the time. Aurelia beat out React in a lot of benchmarks back in the day. I'm sure Aurelia 1 vs React has slipped, but Aurelia was one of the faster options for a while, especially in re-rendering performance. You should give v2 a look. It improves upon v1 in every single way.
my app has actually very little aurelia specific code so i expect this should not be to hard. if only i can find an aurelia 2 equivalent of this version that works without any build system: https://news.ycombinator.com/item?id=36971080
There is a build system free version documented here. Is this what you mean? https://docs.aurelia.io/developer-guides/cheat-sheet#script-...
If you need any help porting it over, just let me know.
https://unpkg.com/aurelia/dist/native-modules/index.js doesn't resolve. i tried https://unpkg.com/aurelia/dist/native-modules/index.mjs which does resolve, but it links to a dozen other files which all don't seem to resolve either. it looks like unpkg.com is rather broken.
with aurelia 1 there was a downloadable archive (which still exists) that had everything bundled that i could just unpack and it was ready to run. it didn't even need a server to host the files if i was running a browser on the same machine.
the original documentation for that is here: http://web.archive.org/web/20160903072827/http://aurelia.io/...
basically there are two things i am looking for:
i want to be able to develop the application without using browser-sync or build steps and it appears the version you linked promises that.
but i also want to be able to host and develop the application completely offline without any need for internet access.
the reason for that is that i am using the application (in production as it were) while i am developing new features or fix bugs that i discover while using it.
running the transpiler in the browser doesn't bother me, it's been fast enough so far.
i would use aurelia-cli if i could figure out how to make it build a development version without browser-sync and without transpiling and compressing the code before it is deployed.
My point wasn't only that these issues exist. If a framework has this many issues that go unfixed for years, while the user-base dwindles, maybe you shouldn't trust the developers.
In addition, I believe that not only the implementation, but the fundamental design that is flawed. There's a reason why UI development has moved away from the OOP/Mutation/MVVM approach. The problems that hooks were intended to solve are real, and every big Framework since React has provided approaches to solve them... except Aurelia.
i really like how aurelia is practically free of boilerplate code, and doesn't force my code and data into specific structures.
No one cares about web components, including people who originally where really bullish on them (Vue, Svelte, Solid). React supports web components just as it supports anything that attaches itself to the DOM, and that is more than enough for the vast majority of use cases.
Meanwhile, if Web Components were any good they wouldn't need another 20 specs just to barely patch holes in their design: https://w3c.github.io/webcomponents-cg/2022.html or still have unresolved issues like "custom button cannot submit a form": https://github.com/WICG/webcomponents/issues/814
> but at least jQuery helped shape modern standards. Has anything good come from React for the platform?
It could have, if the people behind web components listened to anyone except themselves.
People claim other frameworks solve the same issues without introducing any significant new problems. I'll remain skeptic until I see a couple of huge full-functionality apps in those frameworks that manage to keep a clean codebase and good performance.
I've seen too many times people "solving" frontend development, most of the time that solution just amounts to documents linked to each other, and avoiding complex forms and interactivity, but if you just do linked documents, frontend development was solved in the 90s, and you don't need javascript at all.
There is nothing inherent to React that makes it significantly worse than the many other Javascript frameworks out there. At least it has the benefit of having ongoing support by a major vendor with a record of long term support for open source projects. That's not something that is all that common in the Javascript ecosystem.
There definitely are plenty of things which are an order of magnitude harder in react than any other framework.
One flow data is an example, having to install deps for everything from state management to css is another.
All the choices compounds and make complicated projects even more complicated, increasing tech debt.
Don't get me wrong: Angular (and for sure other frameworks I can't think of) had the same problem; many other frameworks do not.
These days I'm very happily developing against Solid Start with not a single issue I can't think of and a syntax which is very close to React.
That is exactly the kind of conclusions that come from not understanding what runs under the hood.
you can have one dev write the front end and most of the server side code too. not only that but they have to handle much of the tooling, testing and debugging.
and the learn2code push also was designed to saturate the market with lots of these devs. many of whom lack the background knowledge to understand what they're doing.
i seen this job expand through the years from a smaller set of responsibilities to a much larger one where most of your work is only indirectly (and irritatingly) related to what you're actually trying to do.
Is this remotely relevant, though? I don't think it is. The whole point of working with higher level abstractions is to not have to care about the lower level bits. We all know that things are not as optimized as they could theoretically be, and that's ok. People are paid to deliver value, and microoptimizing stuff just wastes everyone's time.
I would say that React gives you more work in terms of cognitive load and also in terms of development time if you look at it on a medium to long time-frame.
LibreOffice, Mozilla Thunderbird are of such scale that it's difficult to change these applications how they work today.
> I have a second confession: it’s still not intuitive to me what should and shouldn’t go into the useEffect dependency array, or why...
Come on, this isn't that complicated, I find it hard to take the criticisms seriously when the author hasn't groked React properly.
You don't need to read "multiple articles" about these things, they're explained clearly in the docs
- https://react.dev/reference/react/useMemo#memoizing-a-functi...
- https://react.dev/reference/react/useCallback#how-is-usecall...
- https://react.dev/reference/react/useEffect#specifying-react...
To answer OP's questions, useCallback is
function useCallback(fn, dependencies) {
return useMemo(() => fn, dependencies);
}
As for useEffect, everything that might change between renders, eg props used in the effect, must go in the dependency array.It's fine admitting that hooks are a bit too complex. (don't get stockholm syndromed)
>I’m still not exactly sure what the difference between useMemo and useCallback is
This is actual nonsense. Creation of a fully-formed HTML document server-side is performed by countless platform combinations.
Let's be a bit more charitable when we pull quotes out of context.
In PHP the server computes the full HTML and sends it to the client browser. What would need to be added here to have “client side hydration” for example?
Seems weird to me to use “SSR” as a term for both SSR + hydration, but I’m not in the web dev lingo bubble so what do I know? The author doesn’t use the term “hydration” until the blurb at the end talking about Quik
SSR when talking about React is very clear jargon.
You have a client-side web application. You want the initial-state HTML to come over the wire on the first response rather than wait for the client application to load, make a request, and then render the result.
So you use a tool like those listed in TFA (like Next.js) to run your front-end app logic on the server to generate the HTML and send it to your client where your front-end app mounts to that HTML and takes over (cutely named rehydration).
This is relatively cutting edge stuff which is why it's weird to assume OP is an idiot who never knew about PHP or CGI when he wrote an article that is obviously talking about client-side applications and rendering them on the server.
So I would say the author's point (if I was asked about it) would be that these other new front-end frameworks support similar things, instead of sending plain HTML over the wire.
Am I wrong?
The older platforms for this had you essentially write two separate backends - the one which renders HTML, and the other which returns a JSON or XML API for your hand-written JavaScript (or CoffeeScript or JQuery etc.) embedded in your HTML.
So, considering this, is it still nonsense? (I honestly don’t know.)
And also, mediocrity is part of our life on this planet, and also, a matter of perspective.
In the meantime this one site I worked on, which used Java for server side rendering¹ with a bit of JQuery and custom scripts is still going strong.
1: It's ridiculous to hear JS people say how awesome server side rending is when basically every other language used for the web was server side, sometimes decades before it.