Forms are also hard because they involve many different data-types, client-side state, (client?) and server validation, crossing the network boundary, contextual UI, and so on. These are not simple issues, no matter how much the average developer would love them to be. It's time we accept the problem domain as complex.
I will say that React Server Components are a huge step towards giving power back to the URL, while also allowing developers to access the full power of both the client and the server–but the community at large has deemed the mental model too complex. Notably, it enables you to build nuanced forms that work with or without javascript enabled, and handle crossing the boundary rather gracefully. After working with RSCs for several years now, I can't imagine going back. I've written several blog posts about them[1][2] and feel the community should invest more time into understanding their ideas.
I have a post in my drafts about how taking advantage of URL params properly (with or without RSCs) give our UIs object permanence. How we as web developers should be relying on them more and using it to reflect "client-side" state. Not always, but more often. But it's a hard post to finish as communicating and crystalizing these ideas are difficult. One day I'll get it out.
[1] https://saewitz.com/server-components-give-you-optionality
[2] https://saewitz.com/the-mental-model-of-server-components
Thanks for the point on RSC, probably the first argument I’ve heard that helps me contextualise why this extreme paradigm shift and tooling complexity is being pushed as the default.
Let's not pretend that the Tanstack solution would be good. For example, What if my form changes and a new field is added but someone still runs the old html/js and sends their form from the old code? Does Tanstack have any support to 1.) detect that situation 2.) analyze / monitor / log it (for easy debugging), 3.) automatically resolve it (if possible) and 4.) allow custom handling where automatic resolution isn't possible?
It doesn't look like it from the documentation.
Sorry, frustration is causing me to rant here, but it's a classical thing of the frontend-world and it causes so much frustration. In the backend-world, many (maybe even most) libraries/frameworks/protocols have builtin support for that. See graphql with it's default values and deprecation at least, see avro or protobuff with their support for versions, schema-history and even automatic migration.
When will I not have to deal with that by hand in my frontend-code anymore?
That's your job. Frankly, anything more would be over kill. Why should my url param manager handle new or removed form fields?
So you can never make any breaking change to your api whatsoever? Or, in practice, you don't care and let users deal with app crashes and invalid state? Yep, welcome to the frontend-world.
a) serve an error page, leaving that to the backend (at some point the backend must validate anyway)
b) serve the regular front-end and react to the invalid state with error messages. there are libraries like zod that should make your job easier.
It must happen on both frontend and backend, because it's about their communication with each other. So that includes frontend.
> a) serve an error page, leaving that to the backend (at some point the backend must validate anyway)
> b) serve the regular front-end and react to the invalid state with error messages. there are libraries like zod that should make your job easier.
I mean, that is exactly what makes me so frustrated! Sorry, you are just giving a good example of what I'm complaining about. Both of those solutions are sub-optimal.
Here is how I'd implement that by hand if I would write something like nextjs/django:
1.) The frontend always sends a version in each of it's request (in the payload, the header, wherever)
2.) The backend compares that version against what it is expecting and compatible with. If it detects an outdated/incompatible version then there are two options: it is somehow possible to automatically fix it. For example because the used protocol has some mechanism and the developer uses that (such as default values for missing values) or because the developer has manually provided a migration for old versions.
3.) If it can be fixed, all good. If not, the backend sends a message back, saying that the request cannot be processed because the version is too old. The user can then decide to e.g. save their state elsewhere and reload, or just reload. Or do something completely different.
4.) Bonus: while we are at it, why don't have that fronted send regular requests to backend and ask if the version is still up-to-date (especially if it's the type of user that has their browser tab open forever). That would help to prevent data loss or other problems before they even occur, because the user gets an info and can refresh early.
Why should I implement all of that myself over and over again? Are you guys really thinking that this should not be handled, or at least made very easy, by typical weblibs/frontends such as nextss or django?
Tanstack router[1] provides first class support for not only parsing params but giving you a typed URL helper, this should be the goal for the big meta frameworks but even tools like sveltekit that advertise themselves on simplicity and web standards have next to zero support.
I've seen even non JS frameworks, with like fifteen lines of documentation for half baked support of search params.
The industry would probably be better off if even a tenth of the effort that goes into doing literally anything to avoid learning the platform was spent making this (and post-redirect-get for forms) the path of least resistance for the 90% of the time search params are perfectly adequate.
I don't use HTMX but i do love how it and its community are pushing the rediscover of how much simpler things can be.
[1] https://tanstack.com/router/latest/docs/framework/react/guid...