Hacker News new | ask | show | jobs
by paulddraper 1106 days ago
I'm lost.

React builds interactive UIs (web, mobile). After each interaction, the virtual DOM is programmatically recreated and reconciled to the actual DOM.

But reactpy is running on a backend sever??? Is each interaction resulting in a server call?

Can someone explain what is going on?

EDIT: Ah, okay, thanks. Every re-render is a network call. If people complained about web UI performance before..... :)

5 comments

In reality, an important and large class of apps will hit the backend on roughly every click anyway, and having full control over in-browser interactivity is kind of overkill for those apps. Business apps with tables, charts, and forms, for example. You click the nav to load a new page, you scroll down or click a button to load more data, you fill a form and click submit, all those things hit the server.

For those types of apps, this 'backend-driven reactive apps' paradigm could be more efficient, because programmers don't have the option to build stuff like an inefficient network protocol or bloated frontend stack.

For a certain class of things, this could work.

You'd have to conscious of this.

It's defiantly not a "write a usual React app, but in Python"...every dropdown, menu, modal, etc interaction interaction is a backend call.

What about conditional form elements, modal dialogs with static text, or collapsible menus?

I understand the benefits, then again if interacting with these elements requires calling the backend then the cost is quite high.

Indeed something like a collapsible menu may call the backend to ask to open/close the menu.

But some frameworks may open the prefilled menu when you click it, and sync the state to the backend, instead of waiting for the backend to “approve” the request to open the menu.

Hypothetical example:

  m = menu(1, 2, 3)
  if m.opened:
    print(“It was opened.”)
Here there may not be any UI latency when opening the menu. The menu opens when you click it, and the state is synced to the backend. However,

  m = menu(1, 2, 3)
  b = button(“open the menu”)
  if b.clicked:
    m.opened = True
In this program, there will be a round trip to the backend when you click the button to indirectly open the menu.

Overall, it depends on how you design the framework and how you divide interaction control between backend and frontend. Controlling every little interaction thru the backend is probably not a good idea, and you should bake some frontend interactions into the UI components.

yes, from reading the docs, there's a websocket.

Making a 'server call' on each interaction is also what web apps used to do before SPAs were a thing. And in many cases it's what SPAs do as well.

Of course, it depends what counts as an 'interaction', but that's been the case since JavaScript existed.

> Making a 'server call' on each interaction is also what web apps used to do before SPAs were a thing.

One of the reasons behind the popularity around webapps was that they would no longer need to make 'a server call' on each interaction.

> And in many cases it's what SPAs do as well.

I feel you're grossly misrepresenting what SPAs do. SPAs do calls to send and receive data, not to fetch server-side rendered content.

> One of the reasons behind the popularity around webapps was that they would no longer need to make 'a server call' on each interaction.

Ironically, many modern SPAs are significantly slower than the traditional apps they replaced. Try using Twitter's webapp on a non-premium phone, for example.

Sometimes it's regrettable that the webdev truck has no rear-view mirror.

The entire internet is slower because it's being squeezed to oblivion for monetization and tracking purposes. No matter what technology you choose to render HTML with, your company is going to have a slew of systems for injecting 3rd party scripts, running A/B tests, collecting analytics that include recording user sessions, etc etc. Back "before SPAs" we just weren't doing as much crap in the browser.
Tracking doesn't help but modern frontend development practices lead to slowness.

Rerendering and recomputing too much (ever encountered these chains of map() and filter() in render()?), many API calls, huge icon sets, huge custom fonts, CSS frameworks and JS frameworks, huge dependency trees with many instance of the same lib running sometime in several versions, big bundles... This heaviness in the name of convenience and branding is not free, it forces people to ditch perfectly fine hardware, which has a high environmental cost... not directly paid by people funding the code).

One of my pet peeves is managed text inputs, where render() is called each time you type a character, for a whole component tree if you are not careful and you happen to pass the content to some parent for some reason. Typing a message in Mattermost on the PinePhone is painful for this reason, there's just no reason typing should be slow even on slow hardware but managed component is considered good practice.

Making people buy newer / powerful and making people wait and using too much energy should be considered bad practice.

I agree. I recently went to great lengths in the React app I own to make it so that only the affected components would re-render on each input keystroke, and the result is gross but performant. My opinion is relatively nuanced: I am a proponent of SPAs in situations where they make sense, but if I had a choice I would never use a framework. They always impose at least as many problems as they solve, if not more.

I attempted to build a startup product using a vanilla JS SPA when I was a founding engineer, and the result was predictable: it worked great for me, but nobody I hired wanted to learn some random guy's vanilla JS codebase. I've since resigned myself to using React simply because that's what developers expect, despite all the headaches.

For what it's worth, we ended up migrating to Mithril in the V2 of that startup's product. We all enjoyed Mithril and it scaled really well for us, but my team did have some apprehension about their React skills falling behind.

> Rerendering and recomputing too much (ever encountered these chains of map() and filter() in render()?), many API calls, huge icon sets, huge custom fonts, CSS frameworks and JS frameworks, huge dependency trees with many instance of the same lib running sometime in several versions, big bundles...

This hits the nail in the head.

A single high-res background image weights more than all the code in a complex webapp. If that image is required to pull the first contentful paint then the page will feel slow.

It matters nothing if your JavaScript is just a hello world console log. That background image is in the critical path.

> The entire internet is slower because it's being squeezed to oblivion for monetization and tracking purposes.

Bullshit. All you need to track a user is data you send as part of a HTTP request. Pushing metrics is a fire-and-forget HTTP request away.

The internet feels slower because we're using way more of it, not only in the increased complexity of webapps to improve user experience and implement features but also in the volume of data we're transferring around.

> running A/B tests

A/B tests just means settings/feature flags and metrics. Feature flags is used in way more things than behavioral studies.

> include recording user sessions

User sessions are recorded since ever with zero performance penalty. The very same HackerNews page you're now browsing is tracking your user session whenever you login. That's not it.

> Back "before SPAs" we just weren't doing as much crap in the browser.

Right, and life sucked back then. Why do you think Flash was so popular?

It's trendy to shit on the status quo but it also is low-effort and lacks any insightfulness.

> All you need to track a user is data you send as part of a HTTP request.

Browsers impose a limit on concurrent requests (usually 6 per hostname) for a reason - HTTP requests, be they too many or too large, are one of the largest performance problems in a typical site. Just because it's easy to fire-and-forget an HTTP request doesn't mean it doesn't have a performance impact, especially in apps that are already network-chatty. I think you know this because you go on to list "the volume of data we're transferring" as a performance bottleneck, and obviously that's done through HTTP requests. Also, in the real world analytics installations virtually always include installing a third party library i.e. google analytics, so you're taking hits to download the library, interpret the source, run the code alongside your app, usually in the same thread, all before you've fired any of those HTTP requests.

> A/B tests just means settings/feature flags and metrics

I'm aware of the definition. If you are implying that conditionally loading settings or feature flags and tracking associated metrics doesn't have a performance impact, I would disagree. It is usually possible to implement a given A/B test with minimal performance impact, but in practice these are absolutely a contributor to the kind of bloat I'm frustrated with.

> sessions are recorded since ever with zero performance penalty

It sounds like you're talking about logs. I'm talking about "session replay" features provided by companies like FullStory and Sentry that allow you to replay every mouse move and keystroke of your users.

> It's trendy to shit on the status quo but it also is low-effort and lacks any insightfulness.

By this point in your comment I think you forgot what we were talking about. I was arguing that the architecture of modern SPAs shouldn't bear the blame for bad performance; my point being that whether or not we continued to use server-generated HTML we would still be suffering from similar problems of bloat today. The "status quo" that I'm shitting on is taking lazy approach to performance management and injecting way too much cruft; unless you work for an analytics provider I'm not sure why you would be opposed to that stance.

Hell, try using the Twitter web app on something with 8GB of memory or that's older than 5 years old.
> Ironically, many modern SPAs are significantly slower than the traditional apps they replaced.

All software becoming slower is a already a meme. This isn't exactly a SPA issue.

> Sometimes it's regrettable that the webdev truck has no rear-view mirror.

The "software is getting slower" meme was the Hallmark of Java in the server when it was released in the 90s. This is nothing new, or specific to web dev.

Also, I feel you're grossly misrepresenting the problem. Reddit's mobile page is considerably slower than the old reddit page, but it's perceived performance is quite good. All posts are cached and instead of full page reloads it just switches content virtually instantly.

It might be fancy to shit on everyone else's work, but this only happens if you lack objectiveness and sincerity.

Yep. And nowadays you can deploy apps really close to users so latency is really low. If you have <100ms you don't really notice the latency.
But... 99% of insert-startup-product-built-on-React (or honestly, any framework) is typically super slow (for whatever reason that might be). Sluggish, not super responsive, laggy UI, however you want to describe it. A far cry from the snappiness of desktop apps from 25+ years ago.

Something or some collection of people are doing something wrong, somewhere in the chain. So isn't this just yet another way to further entrench the modern state of meh-ness in performant UI?

Your statement is very broad. Might be the startup culture and lacking technological expertise, no?

Was insert-startup-product-built-on-.NET fast 15 years ago, for example?

Not trying to be controversial, just wondering.

I agree that a product built by clueless developers stringing together random libraries or bad custom code in React would create slow products.

In your spirit, I might argue that thinking "reactively" and client-centric tends to lead to unneeded requests.

Developing without meaningful API contracts or basic CS skills also makes it easy to unintendedly blow up network payloads.

Caching is hard though.

Have you worked on bad PHP applications that reload on every interaction without caching?

As someone who has had the misfortune of working on poorly tuned WordPress and Drupal websites in a former life I can confirm this is an issue of culture, not and axiom of whether SPAs are intrinsically faster or slower.
manual network state sync between frontend and backend is the root cause of that
> A far cry from the snappiness of desktop apps from 25+ years ago

So apps without network latency are faster? Huh.

People notice the difference of < 10ms in input delay on a command line. I am pretty sure humans notice stuff >= 10ms, <= 100ms. It is perhaps the expectation, that is different. People do not expect websites to react immediately, like when they are typing a command in a terminal emulator.
> And nowadays you can deploy apps really close to users so latency is really low.

That sounds like blindly throwing money at the software architecture problem you created for yourself. Supposedly SPAs became popular because your line of reasoning was embarrassingly absurd, in the sense that you do not mitigate the penalty of a network call by microoptimizing the cost of a network call.

Proximity is only part of the equation. If a user has a slow router or a busy corporate firewall to go through their timings can be far higher than 100ms even if the server is a few miles away.
A no-op API call to FastAPI takes more than that. Even when running on localhost. And FastAPI is one of the better contestants.
If fast api didn't use pydantic (the slowest library in that space), I'm sure it might be more deserving of the name :D

Microbenchmark to compare with typedload (which I wrote) and apischema https://ltworf.github.io/typedload/performance.html

Note that pydantic and apischema use .so files, while typedload is just pure python code.

A no-op localhost call takes more than 100ms??
On my mobile i5 10-gen it's 23 ms.
Yeah this seems to combine the worst of both worlds: react headscratching (e.g. why useEffect do this weird shit) and slowness of the phoenix style send it all back to the server. The solution? For python people: learn some JS and use django.
The most popular stable diffusion UI uses gradio, which is the same paradigm of defining a web frontend in the backend, and the performance just falls apart after the code reaches a certain size. The need for most interactivity to roundtrip to the server and back opens up tons of places where a bad connection could leave the whole app in a half-broken state. And beyond that, it's just slow. So much so that mobile use on cellular is out of the question. Other SD user interfaces handle parameter adjustment in the frontend, but something as simple as swapping two integer inputs requires an seconds-long API call unless you bypass the whole framework with custom JavaScript.

Then there's the fact that your backend framework has to define the subset of all frontend features it supports in Python. The moment you hit on a usecase that isn't supported in Python, you have to learn JS anyway and write code in the frontend. Except it's the worst kind of frontend code: hacks around broken or missing frontend features that depend on implementation details specific to the framework that are subject to change at any time.

I feel that these kinds of frameworks are better suited towards researchers or backend devs who really do not want to have to set up an NPM project just to have a simple (and I really mean simple) frontend UI to interact with. But don't dare try to write the next gigantic ML app on top of it or you'll have to deal with the performance and maintenance issues that follow.

I mean, what if the app is only ever used by one person over localhost? Seems you would be blocked on access to the GPU, unless it also has GPU farm support?
I meant more in the context of basic user operations feeling sluggish and degrading the overall UX.
Sounds like Elixir LiveView.
That's how the new "react server components" work too. It's more sophisticated than this but the network concept is the same.

Blazor was the pioneer here.