Htmx vs. React: A Complete Comparison – Semaphore
semaphoreci.com
semaphoreci.com
In the traditional browser model that HTMX espouses to emulate and improve on we have form resubmitting (with a warning that it will resubmit data), we have different errors for if the server returns an error or if your wifi disconnected, etc. Those errors are perhaps not well designed, but they are there and explain what is happening. With HTMX (at least when I tried it) it just got swallowed and one had to write client side code to handle it.
You're definitely correct that the htmx documentation and tutorials and such don't talk about error-handling as much, and that should change! This is partly a function of how relatively young htmx is, and how long its been since the industry focused on hypermedia-related error handling patterns, so I'm optimistic this won't be the case for too much longer.
In the meantime, what I usually do is write a tiny htmx config snippet that intercepts 4xx or 5xx responses, and inserts them as a modal/popup/alert in the DOM. You can also do the opposite, and hook into an event from before the request, and do something with it if the requests fails for other reasons. Another common pattern is to return an error modal from the server and target the "error" spot in the DOM. There are also extensions for handling different response codes differently.
But again, while it's very do-able and I think reasonably intuitive once you start building larger apps with htmx, it's still an undeveloped aspect of the educational materials :)
htmx doesn't promise to do away with client side code. Most uses of it I see still have client side code. They tend to go in one of two directions with it.
1. Web Components to encapsulate client side error handling and behavior.
2. The hx-on attribute for scripted event handling.
It's not really an anti Javascript library. It's more of a different approach to server side state synchronization.
I have to dynamic apps I use for personal usages. One is an offline first spa app so htmx won't work well for it. It's all client side code with json apis. The other has no offline use case and htmx is a great fit for it but I still have several hundred lines of vanilla javascript in there for client side behavior bits.
What happens, for instance, if the the request times out?
Also, the main reason, I feel, for actually wanting to use react is if you have an application with data that has a complex relationship with the UI. I don't know the technical term for this unfortunately, but the idea is that state management through, say, redux allows data changes to propagate throughout the UI. HTMX doesn't appear to address this at all. In fact, it seem like very brittle relationships between htmx elements are established. It is equivalent to a jquery + id nightmare.
htmx triggers an event: https://htmx.org/events/#htmx:timeout
Then you, the developer, optionally handle that event and show a message to the user (if you want).
Sometimes it does make sense to send back an HTML fragment with an inline error message, or a fragment that gets injected as a toast notification. Other times you may want to redirect to an error page with a full page refresh. Depending on the HTTP request method used, you may be able to return an HTTP error response too.
Sooner or later you need to handle these different errors, and I don't think HTMX has these sort of "non-happy" paths at mind.
1) application errors (e.g. bad data in a form)
These should be dealt with the "normal" way: rerender the form with error messages on them. Most good server side frameworks w/ form integration make this easy, and you can see an example of that here:
https://htmx.org/examples/inline-validation/
2) server errors
These are things like 500-level errors, 404s, etc. In this case htmx does not swap by default, but you can modify that behavior if you'd like to have it swap (and retarget, etc.)
3) network errors
On network errors, htmx triggers events such as htmx:sendError, that you can handle and show an error message, etc.
By and large we get almost no support issues around error handling: it is fairly obvious how to make things work if you are familiar with traditional web applications and more complicated things like connectivity issues are handleable via events, which isn't complicated either.
One thing that does occasionally bite people is when server-side frameworks respond with a 422 response code for application-level errors and try to rerender a form with those error messages. By default htmx will not swap that response since it is not a 200-level response code. You can modify this behavior here:
https://htmx.org/docs/#modifying_swapping_behavior_with_even...
If I had it to do over again, I would consider making 422 responses swap by default.
Regarding the "resubmit" warning, that doesn't apply to htmx-powered applications because AJAX operations don't naturally end up in the history chain. This means that the Post-Redirect-Get pattern isn't needed.
Error handling isn't a particularly hard aspect of htmx. What is hard is adjusting your mindset to the hypermedia approach, particularly if you are very deep into reactive programming. And there are applications that this approach is not suited for:
https://htmx.org/essays/when-to-use-hypermedia/
However, when your application is well suited for the approach, htmx (or similar approaches) can be a very big win:
React-dom alone is 42kB gzip.
You might remember when a thing called DHTML revolutionized how JavaScript could be used to build interactive UIs on the web... why go back to pre-2001 era?
I get it, SPAs are overkill, but swinging the pendulum all the way back is very strange.
https://hypermedia.systems/client-side-scripting/
I can understand the objection to the first request but the second is necessary to update state on the server. You could avoid the first request via scripting but the complexity, in my opinion in most cases, would not be worth it.
You might find https://data-star.dev/ interesting, it takes some of the modern approaches (signals, etc) and mixes it with the efficiency of sending straight-up HTML, htmx style. It's very similar to using Alpine + htmx together.
Not sure how long it'll be until the htmx part gets rationalised out in those instances. Maybe it won't, and people will keep shipping both. Stranger things have happened
Is it preact? Svelte?
With react you get somewhat prescriptive low-level patterns when it comes to "managing data flow", so I would probably use react to keep things consistent.
Used to be, but you are right that JSX is a rather thin syntax over function calls. (The modern JSX transform now uses a _jsx and _jsxs call, depending on whether you are rendering a single child or an array of children).
See https://legacy.reactjs.org/blog/2020/09/22/introducing-the-n...
Much React work these days is confined into components, people sadly over-do it also because they perceived Redux as overkill and try to shoehorn entire applications into core React hooks (that are mostly designed for smaller components or at most views).
This is needless when Redux (with Redux-toolkit) has recipies that solves the whole-app dataflow problems well (people have issues with Redux because their components got overly complex in the past by shoehorning component issues into Redux instead and now they're complicating things in the other direction).
First rule of not messing up React/Redux: Don't mutate data, 90% of messups I see with fresh people is breaking this. Everything should become transforms! To accomplish this the spread operator (...) in JS/TS along with map/reduce/filter are your biggest friends. (You can do optimizations but 98% of the time you won't work on big enough datasets that you need to do that)
Thus when you do setX (of state hooks) you set your transformed data, same with sending messages in Redux, your Redux reducer acts upon a message to transform the internal state.
Joking aside, you're right, often it's almost easier in recursive cases to just go with flat object lists and keeping identities on objects and keep parent id's around.
In my view, React is a theoretically beautiful piece of software, and if you're planning on building a synchronized networked system keeping in line with what makes it beautiful will give you it almost for free.
For many practical cases (especially smaller SPA's/pages) however it's probably better to just go with Vue or similar and mutate away and let the system handle all update checks for you instead.
There's only two kinds of data inside a component (class-based), first is props. Props is, similar with html attribute, are given to the component by the caller / owner / parent. `<input type="password"/>` has type as the props key, and "password" as it's value.
State is data that lives inside a component and cannot in any way accessed by the caller / owner / parent. It can only be accessed by the component itself, or it's children if the component decided to pass it. In general, you'll use very few components with state in a single application unless you know what you're doing with it.
So about the data flow, generally data is handled (can be via state or state management libs, see later section) by higher ups (parent) component, and passed to it's children via props. Now the parent component, together with the the value passed, also pass function. The function can be called by the children to update the parents state.
As for data management, there's 2 way I usually handle it. First is using state management like mobx and passing it via several ways, usually using react context. State management libraries usually has section on this.
Second is to declare the data I needed on top most components (that's relevant to the data itself) via react context, and pass them either via props or make children access them via react context.
Other than being overly verbose, I think React is ok after building my website with Sveltekit. There just seems to be way more support for off the shelf react components and 99% of jobs ask for React.
They shine when you need / can separate the business logic with ui. Think about state management as "backend" for your frontend.
What props they have, whether a function will change which props, etc, are belonging to state management. Heck, even the state management can be done in separate project by different team.
The best thing, in a bigger org / bigger project, you can have 2 state management code. One is mock, for frontend to develop, which has no dependency with servers, and another is the real one, that really call the backend server for real data.
I found it useful to actually work through the React tutorials.
Keep things simple and learn the simple use cases first.
The world of React is now a very busy place, so trying to jump in to a full stack can quickly become overwhelming!
FWIW I'm not a fan of how many React and GrpahQL frontends are built. For me it's a lot of complexity for little gain and plenty of pain!
Hooks are frankly something that you just have to put work into learning though as they can’t be succinctly explained. It’s worth the effort though.
Where ordinary programming paradigms result in tangled and messy state, and pure functional paradigms try to pretend state doesn’t exist and stick it all in a monad, hooks provide a framework to handle state in a way that composes much like pure functions do.
The return of a component render is a description of more work to do. When that’s done is up to reacts scheduler.
Once react has rendered a tree it then commits it to the dom.
Manipulating dom elements at runtime is imperative work. Doing it server side you get the same declarative capability as react, but no runtime behaviour.
React elements not being 1:1 with the DOM is what enables us to also target native, tuis, and so on.
What are your specific pain points?
JSX is HTML-like syntactic sugar, just write normal html but put JS stuff in curly brackets.
Data management can be tricky at first, but as long as you remember that everything that isn't memoized (via e.g useState) is recomputed on every render pass, you're 90% there.
You can get into the reeds of it of course, but you really don't need to if all you want to do is just build a regular app.
and what kind of data management do you mean? for a SPA most people use react query in place of redux these days, otherwise with something like remix you don't need any external data lib
https://wptavern.com/interactivity-api-prepares-for-its-offi...
https://bundlephobia.com/package/htmx.org@1.9.10
the authors are confusing it with another package:
> Goal: Add modern interactivity features directly in HTML vs Provide a component-based, full-featured UI JavaScript library
Ah, no. Anyone who's used React.js should know otherwise. React is a declarative view library. It doesn't even handle routing or app state management, let alone the requirements for a "full-featured UI."
> [React] Features: [...] one-way data binding, state management
These statements are between "weirdly put" to "outright wrong."
> Learning curve: [Htmx] Gentle v. [React] Steep
React is dead simple. Your `HelloWorld = () => <button onClick={console.log}>Hello!</button>`. The learning front-end development can certainly be steep, but React is light-years away from kitchen sink frameworks that have you fiddling with yet another templating engine, controller classes, etc.
> React: A full-featured JavaScript library for building user interfaces based on reusable components written in JSX
This conflates React, ReactDOM, and JSX.
> Because of its unique approach to web development, React has a steep learning curve. Before building your first React application, you need to understand the concepts of SPA (Single Page Application), Virtual DOM, JSX, state management, props, re-renders, and more. This may overwhelm some beginners.
You don't need literally any of this aside from `props`. If you do use JSX, then its syntax will feel far more familiar than `hx-get` or whatever.
> SPA applications built in React usually contain a lot of JavaScript. That results in higher network utilization and client-side rendering times.
This conflates React with frameworks like Create React App. It ignores alternatives with SSR like Next.js. Also: don't encourage people to make more SPAs with React. Please.
Doesn't it? [1]
> another templating engine, controller classes, etc.
Template engines are easier than React, considering it's generally as easy as {{ and }} inside html.
Controller classes? It's as simple as print('<html><button>Hello!</button></html>')!
> If you do use JSX, then its syntax will feel far more familiar than `hx-get` or whatever.
Definitely not. Few attributes is a lot easier than JSX.
TypeScript is not typed fwiw, e.g. `as any`.
So because it has a feature to disable typing it is not typed? Would you say the same thing for any language that has similar "unsafe" flags, like rust or basically all the others?
| Static | Dynamic
-------+--------+---------
Strong | Rust | (lisp?)
Weak | TS | JS
TypeScript bolts on a Static type checker onto JS, and the types are erased before running in a real JS runtime. At runtime the types can change out from underneath you for many local and nonlocal reasons. This is simply impossible in Rust in general.Rust unsafe features don't allow you to override type safety, but you can directly manipulate raw pointers if you're so inclined.
TypeScript really does let you bypass the type checking entirely and drop down to just JavaScript.
I'm not sure how that makes typescript "not typed".
Many languages do have sound type systems, and I would argue we should prefer those.
This is reasonable, given that untyped data received at a system boundary is going to need some kind of type checking no matter what the language or type system; I'm not sure that can even be fairly called a 'problem'. But it also would leave the putative line of argument rather footless, in that blaming Typescript for something Rust also requires is incoherent.
Perhaps the originator of the claim under discussion will clarify his meaning.