Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I believe functional is the better (and best) paradigm we have right now. But the problem of why FE development still feels overcomplicated is because of a different reason.

There's a mismatch between how components are organized and how data flows through the front end application.

HTML is hierarchical. You have elements wrapping each other

   A
   └─ B
       ├─ C
       │   ├─ C1
       │   ├─ C2
       │   │   ├─ C2a
       │   │   └─ C2b
       │   └─ C3
       └─ D
           ├─ D1
           ├─ D2
           │   ├─ D2a
           │   └─ D2b
           └─ D3
The issue here is that you can have something like D3 changing the state of an element like C3. So data must be artificially grafted on the above hierarchy to make it work.

D3 wants to send data to C3? Well then that means B must be the owner of the data. So data that feels like it must live on D3 well now you got to make it live on B which has nothing to do really with D3.

This has one primary problem.

It destroys modularity and much of the benefits of functional programming making it sort of useless in react. If you did prop drilling most things that have a path from B to C3 and B to D3 now are no longer modular and can ONLY be used in context of data related to D3. If you didn't use prop drilling and used some contextual way to pass the data the problem is still there because now components on that path have access to contextual data that's irrelevant. I mean for a time it may be safe... but some developer may break it and have a component access that context and suddenly modularity is broken... that component can now never be moved outside of the context.

Really... how data flows through your program is actually a separate graph structure, and how HTML elements are organized in your program is another separate graph structure we try to graft into the first one and that creates a mess.

I think the best way to do this, hasn't been done yet. But really side effects like clicks and button presses should NOT live on components. Components don't know about these things. That keeps the hierarchy and modularity of these html elements pure. A framework that's well designed needs to enforce this separation. I even think this can be done in a way that is STILL functional, but not react.

HTML and jquery were sort of going in this direction, but the problem was HTML lacked modularization because you couldn't group tags into a component. You also have timing issues and complexity with state that jquery didn't handle.

Overall I think the old style was actually better. It was a better overall direction that had tons of problems and I think those problems could have been solved if we continued in that direction. AND i feel we could have continued this direction with some sort of functional framework.

Imagine something similar to jquery but this jquery can only directly reference components on your component hierarchy and pass data directly to components (aka manipulate them). Context and state will also live on this jquery like framework and it will be handled in a similar way to how react handles it. While components themselves can wrap other components, and parameters that go into components can ONLY have default values. The components can never dynamically "call" other components with data and actually have anything truly dynamic going on.... only the jquery like framework can do this.



Bonsai is a frontend framework that models data as an explicit graph, separate from any “component hierarchy” or DOM structure. State can live anywhere in the application graph, whether or not it’s associated with DOM nodes, and you eliminate all of the “move this state to the parent to share it” ceremony by just having “components” return their views and “outputs” at the same time (if they want).

It’s pretty great and hard to imagine going back to a React-like component hierarchy.


Oh nice, it's ML style, like elm.


> Really... how data flows through your program is actually a separate graph structure, and how HTML elements are organized in your program is another separate graph structure we try to graft into the first one and that creates a mess.

My team migrated away from Redux and for over a year I’ve been unable to pinpoint why I’ve been longing for it again. This has hit the nail on the head for me. Redux (and other “global” state management solutions) allowed me to decouple the data graph from the UI graph. When a UI event is triggered, an action is dispatched and then the data graph takes over. This makes the UI graph extremely simple - render UI and dispatch actions - but these days we’re mixing state with business logic, event handling, API calls, rendering UI, styling, etc. This is very much a problem of our own making that could be solved by a different architecture, but yeah… thanks for clarifying this feeling for me.


Yes but this doesn't solve the problem fully.

because any component that uses that state management solution becomes coupled to that global state. So let's say I want to use such a component in context of a completely different "global" state, then I can't do that anymore. Global state only saves you from prop drilling where you have to insert props into every parent element above the relevant element.

Believe it or not Jquery + html actually did the seperation of data flow and GUI much better than react.

The question is, how do I get re-useable GUI widgets that are decoupled from state all together such that every widget on my SPA can be reused anywhere on different global contexts and even on different apps. React does NOT solve this problem.


IMO/IME these problems have more to do with program organization rather than with any individual architecture.

To avoid it, funny enough, you have to take cues from functional programming, and you need strong, composable, primitives with succint interfaces (the opposite of shadcn). Even for visually combining and placing components, you need stateless layout components [1] that don't depend on anything and just render children a certain way. This way it's possible to have a very flat component hierarchy. The entire state-logic at the top-level doesn't hurt much anymore. Also, just props+events are enough, no need for Context, Redux or other tricks.

But if you go the "Clean Code" route and the main reason to have components is so so they're not too big, then you get deep hierarchies, prop-drilling becomes a big problem, and you need Context or state libraries specifically for inter-component communication.

This is a problem that I've seen come up time and time again not only in Frontend but also in desktop apps and in video games. And backends often have the luxury of having the entire state in the database, so it doesn't happen as often.

Of course the side effect of this is that you will end up with bigger components, and you need better abstractions, but IMO this is a small price to pay for having code that is easier to work with and doesn't need special ways for handling the data. Also this method tends to work better in bigger apps and people complain it's wasteful in smaller apps, so there's that too.

[1] In the design world this is often called Templates. https://atomicdesign.bradfrost.com/chapter-2/#templates It's interesting how this didn't catch among frontend devs. I remember "layouts" being a big part of WPF for example.


hard disagree.

With prop drilling how do you get the setter methods into C3? You have to prop drill all the way down.

Let's say I add a new component under C3 that has a side effect in some sister hierarchy under B. Then now suddenly in between and B and C3 and the other component I have to modify EVERYTHING to take that new change into account and these components now all have an extra prop that they don't intrinsically need but they keep in order to account for C3.

Because data is so intrinsically linked with components Every component between B and C3 now needs to be modified to prop drill when previously it wasn't needed.


This is true of any basic function call hierarchy. Lots of functions in every program's call tree are just passing around values they don't explicitly need but that some callers deeper in the call tree will need, so what you describe is a solved problem at its core: to avoid having to explicitly pass parameters that you don't use around, and having to modify whole call trees when those parameters change, lift those parameters into a data type. Then changes to parameters only have to be made in two places: the data type definition to add a field, and the initialization point to in initialize that field.


Right but the problem here is that you have two hierarchies in react.

You have the HTML hierarchy which is the GUI, and then you have to force data to follow that hierarchy, when really only two components are relevant here. But with react you have to prop drill things all over the place.


> how do you get the setter methods into C3?

> Let's say I add a new component under C3

Simple: you don't.

The entire point of my message is about not having the hierarchy be that deep.

I don't see what you're disagreeing with, as it seems you didn't get that my message is about architecture, not about a panacea solution.


But the hierarchy is arbitrary. It's dependent on how you structure the GUI. You're saying to deliberately not let the GUI have deep structures such that the data won't need to prop drilled? That's unreasonable. Complex GUI's will inevitably have complex nested structures with many things that cause side effects.

That's the problem. Data is coupled with GUI. React can't uncouple it.


> Complex GUI's will inevitably have complex nested structures

Not really.

And that's the thing: while this is the usual way, it doesn't have to be! But it does require a shift in mindset from the traditional way people partition components in React.

All I'm saying it is possible to structure the component hierarchy in a way that is independent from what the GUI looks like. By not having a deep hierarchy, you don't have "deep hierarchy problems".


>And that's the thing: while this is the usual way, it doesn't have to be! But it does require a shift in mindset from the traditional way people partition components in React.

So I'm forced to follow the mindset of making the GUI less nested and less complex because data flow requires it? I don't like it.

I prefer to be able to do anything I want with the GUI. The complexity of GUI and the complexity of dataflow should be completely independent.

>All I'm saying it is possible to structure the component hierarchy in a way that is independent from what the GUI looks like. By not having a deep hierarchy, you don't have "deep hierarchy problems".

Isn't it better to have components also independent of logic and side effects? Why am I forced into some specific structure for the sake of data flow? I still don't like this option. I want these concepts decoupled.


This seems to be going in circles.

> I prefer to be able to do anything I want with the GUI

I didn't say you don't need to stop doing "complex GUIs". What I'm challenging is the assertion that "Complex GUI's will inevitably have complex nested structures". This is not true IME.

> The complexity of GUI and the complexity of dataflow should be completely independent.

And this is exactly what my suggested method achieves. But I'm doing this by going one step further and decoupling the visuals from the component hierarchy. I'm still separating parts of the page into components, I'm just using an alternative to deep hierarchies, and forcing myself to have better reusable abstractions rather than single-use components. I do this with richer primitive components and layout components. That's it.

> Isn't it better to have components also independent of logic and side effects?

This is exactly what I am proposing. What I propose requires keeping logic and side effects from the reusable components. All I'm saying is that the logic shouldn't be distributed among multiple small components, because there's no intermediate layers with single-use components. If you do this, there's no need to worry about the organization you complain about.

In a gist, it's more "Philosophy of Software Design" and less "Clean Code", but applied to React.


>And this is exactly what my suggested method achieves.

Disagree. Highly. Component hierarchies fundamentally tied with HTML and CSS and therefore Also tied with visuals.

Data is also tied to components as that's where it lives. Thus GUI and data are tied together fundamentally in react.

Perhaps you can elaborate. Because as far as I can tell what you're saying doesn't make any sense.


> Component hierarchies fundamentally tied with HTML and CSS

Once again: no, not necessarily, and definitely not fundamentally. Perhaps that's where you can't see where I'm coming from.

You can have more than one DOM level per component, and you can also have children/slots. Components don't even have to render anything. Thus GUI and dataflow can be 100% decoupled.

What I mean with all of this is "keep the React component hierarchy flat and use layout and richer primitives that will render THE SAME nested DOM that would be rendered using nested React component hierarchy".

The point is not changing which and how the final DOM looks like, or the design. The final HTML can and will stay EXACTLY the same with a flatter component architecture.


Are you saying something like this?:

  function TwoColumn({ left, right }: { left: React.ReactNode; right: React.ReactNode }) {
    return (
      <div className="grid grid-cols-[240px_1fr]">
        <aside>{left}</aside>
        <main>{right}</main>
      </div>
    );
  }

  // Flat usage
  export function Dashboard() {
    return (
      <TwoColumn
        left={<NavTree />}          // could itself render nested <ul><li> DOM
        right={<ContentArea />}     // arbitrary component
      />
    );
  }

But this is just bundling the props on a component and using the component itself as a bundle to drill down.


It's not just this, but that's one technique.

However this example has decoupled component hierarchy and HTML hierarchy. Which demonstrates they don't have to be coupled.

> But this is just bundling the props on a component and using the component itself as a bundle to drill down.

But there is no prop-drilling needed, as long as NavTree and ContentArea are also UI primitives. If you need NavTree and ContentArea to communicate with each other, for example, they're now siblings in the hierarchy, even though the HTML hierarchy is as deep as it needs to be for the design.

Btw: If "NavTree" and "ContentArea" are not primitives, they're the kind of thing that breaks a flat hierarchy and require prop-drilling/context/redux/etc in the first place. This is where one would use configurable primitive components, rather than the "Clean Code"-style extracted code.


that's because you are using react where every html element that does something dynamic is its own component.

when i use aurelia, then the whole page is one component and dynamic functionality in elements is achieved through bindings and functions that all share the data in the component. you can include other components, but you only do that where needed, and then passing data becomes a lot easier.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: