Hacker News new | ask | show | jobs
by umvi 19 days ago
Not everyone is building complex UIs like google sheets. Most people are building static pages with a sprinkle of interactivity, or maybe form pages for doing CRUD.
2 comments

It starts as simple crud, but then product introduces a business rule where some fields need to be hidden when another option is selected somewhere. O, but not when this checked, etc. Having a reactive framework when this happens is very much needed to keep all these effects working without a lot of vanilla JS.

This can be solved later, but is a lot harder when you have an entire application that needs to bee kept working, and almost trivial if you started with some reactivity built in.

A lot of rules like "some fields are hidden / shown based on other fields" come from restricting users to only expressing valid object states. E.g. I have a form where a user can pick a "notifier". They get a first dropdown select which is email or teams-message. Then based on that selection to get another which fills the details relative to that.

In that case, the backend will likely have a class instancr representing it, with the first field being a discriminator on the class and the remaining fields being the details. And regardless of what the frontend does, the backend will revalidate always because you can never trust data sent from a frontend.

All that to say, maybe the form could be server side rendered, with an adaptor to convert a class definition into an html form fragment, and either embedding the js "rules" into the html itself, or making it a web component for containered usage.

Doing it this way is a big deviation from the current status quo, but I've found it to work very well and cut out a whole range of bugs. Plus it makes me think about what is truly client side state (no chance of staleness) vs server state cached in client to avoid repeat server calls (could be stale, leads to bugs).

Your first thought might be to use React, but in prior eras we wrote a function updateFieldVisibility() and that worked fine. Straightforward code can be faster than using a state management framework to determine exactly which fields' visibility changed.
But it's harder to have component composition. Consider also lists and adding/removing items and so on, juggling all of it gets insanely complex and requires MVC or MVVM patterns like with backbone.js
But now we're back at "Not everyone is building complex UIs like google sheets". I agree with the underlying sentiment of this thread: overengineering is way more common than underengineering.
Eventually each crud form evolves into something more complex, the bar is set higher today, we expect pagination, filtering, search, inline editing, grids, instant validation, auto-save, push notifications, state sync, ... that's not a complex UI nowadays, it's expected. Not sure what a non-complex UI looks like.
You just call updateFieldVisibility() every time the list selection changes and don't worry about the redundancy.
it can be faster, but is it correct?

React was invented because jQuery style state management collapsed into unmanageable code past a certain size

And it wasn't composable, state was kept in the DOM. Even with higher level libs like backbone we didn't have a component-oriented way like now. Each component had to manually manage all of its child components.
It composes to one level. Each <input> is a component. Is that good enough for your application? For many, it is.
Really sorry to have to say this, but I feel like I'm getting underpaid for the work that I do if people make a living clobbering together input elements and calling it web development.
> but then product introduces a business rule where some fields need to be hidden when another option is selected somewhere

  function initWidget(root){
    // Or a bunch of calls to document.createElement, whatever you want.
    const inp = root.querySelector('.input');
    const check = root.querySelector('.check');

    function update(){
      inp.style.display = check.checked ? 'none' : 'block';
    }
    check.onchange = update;
  }
> O, but not when this checked, etc.

  function initWidget(root){
    // Or a bunch of calls to document.createElement, whatever you want.
    const inp = root.querySelector('.input');
    const check = root.querySelector('.check');
    const check2 = root.querySelector('.check2');

    function update(){
      inp.style.display = check.checked && !check2.checked ? 'none' : 'block';
    }
    check.onchange = update;
    check2.onchange = update;
  }
Compare to React:

  function Widget(){
    const [check1, setCheck1] = useState(false);
    const [check2, setCheck2] = useState(false);

    return <>
      <input type="checkbox"
        checked={check1} onChange={e => setCheck1(e.target.checked)}/>
      <input type="checkbox"
        checked={check2} onChange={e => setCheck2(e.target.checked)}/>
      {check1 && !check2 && <input type="text" />}
    </>;
  }
Compare to Svelte:

  <script>
    let check1 = $state(false);
    let check2 = $state(false);
  </script>

  <input type="checkbox" bind:checked={check1}>
  <input type="checkbox" bind:checked={check2}>
  {#if check1 && !check2}
    <input type="text">
  {/if}
IME almost none of the complexity in any of the web applications I've worked with has been mitigated by the front-end framework in use. You still need to write the code to do the thing, whatever that thing is. You might as well write it in the framework that gives you the smallest bundle size and the best possible backwards compatibility, and that's vanilla JS + the standard web APIs.
I'm not reading the code on HN but I do second this. After implementing a enterprise level production app by myself months ago with vanilla typescript, I find it's much easier to think the vanilla way than adapting to React or things similar. Before this project I work with React for years and never looked the other way. The reason I chose vanilla typescript over React is for performance as the app requires tons of resources and I want to keep it minimal without the performance punishment, but ended with a much better experience for UI development.

You don't need to remember how to properly line up useState/useEffect/useCallback and all.

You could just insert any simple state object and be ok with it, or insert a well-known state management library and it still works the same way.

For UI libraries they almost always have a vanilla option, and even better, if you are not working with google sheet level of stuff, vanilla element management is much much easier to work with.

And no need to talk about the style frameworks, they always work the vanilla way.

With some default vite configuration, nothing you need to worry anymore and the framework level stuff are simple and easy to understand and is totally manageable.

As I said, any app with at least a "moderately complex UI". If your app is just a sequence of web forms and stays that way forever, then you're not the target audience of a UI framework anyway.