This seems awfully similar to the Elm model of managing state. Perhaps it's me being unenlightened, but I never understood why all state in an application needs to be managed centrally. Take a select box for example, its open-state is not something I think a central store should necessarily know about right?
I always find that if I want to write an app in the Elm style (or with Redux), I have to traverse up the tree every time I am working on a leaf node. Each input field in a form should not necessarily cause me to have to rework everything up to the root node right? Am I doing it wrong, or am I just missing what benefits this approach brings to offset this extra development cost?
I'm not a fan of the "global state as a default" approach. There are definitely advantages. It is easy to reason about and to test, and is attractive from a purist point of view, but its usage can definitely add redundancy and complexity to the code with current tools.
Especially for server-centric CRUD apps with forms and lists, this is often abused. If you're reloading lists when navigating to them, and fetching form data when updating a record, then you don't really need global state. If you want to cache, perhaps a plain cache is enough.
If you need some piece of data to affect multiple components in different parts of the hierarchy, sure, make it global, but if you can get away with mostly local state the codebase will be simplified. IMO.
I don’t find global central state easier to reason about. It’s inherently more complex managing the state of a component far away from it in some other place. But I think it’s often worth doing because it enables you to make better UIs. There are many situations where, with two seemingly unrelated components, it actually is better if there is a subtle connection between them - eg. this menu should auto-close if the user started interacting with another component except during some specific other state). Such cases are often not obvious until you are playing with a prototype, they can’t be planned for. And these cases are common, if you are going for a really good UI. Having each component locally manage their state makes it unreasonably complex and nasty to add such couplings.
I 100% disagree. If there's need for centralized state for certain pieces of data, make it so. But premature usage of global state under the guise of "I might need it in the future" is a plague that makes apps much more complex than they have to be.
There's zero need to make everything be the same. There's not even the need to keep state in one single place: you can control all the state and its transitions locally but then "copy" to state management if you need it somewhere else. This is a perfectly valid solution too.
Another problem of using global state for everything is that it reduces the possibility of using a lot of component-level or hook-level abstractions that would be otherwise very useful. You're now forced to do everything through Redux or something like that.
There's no need to rush for an "absolute" solution with all that overhead as if it was a golden bullet. It's not.
Having it globally makes serialisation of the state possible and it can be useful for testing. having no hard line between global and local state can speed up development.
the issue is that current frameworks make global state awkward to pass around. if this were fixed then global has all of the advantages.
Some state (generally, the stuff you would want to persist) should be global.
Some state (e.g. widget animation or your select-box example) should be local.
> I always find that if I want to write an app in the Elm style (or with Redux), I have to traverse up the tree every time I am working on a leaf node. Each input field in a form should not necessarily cause me to have to rework everything up to the root node right? Am I doing it wrong, or am I just missing what benefits this approach brings to offset this extra development cost?
In Elm specifically, you should not have state in the form elements. They should only have component-specific update functions like "Checked" / "Unchecked" that are mapped to form level messages and of course the view function.
You can have both local and global state. That checkbox sounds like it should be handled locally. However, if it's part of a bigger scope (e.g. a form) I would still put the state somewhere central, like in a form context or even in the global store. It's not unthinkable that another part of the form may affect or want to read the checkbox state in the future. You would probably also want to bootstrap the form with previous data when editing, which becomes trivial if it just listens to a big state tree representing the form instead of manually passing default props to the component.
And no, you don't need to to prop drilling when using contexts or a state manager.
One of the parts that I loved at the beginning of my React journey was the component'ization -- the eschewing of "model-view-controller", because really? is that always the best cut-line? How about I do the unix model of a component -- do 1 thing and do it really well as in your select box example.
Anyways, the tide turned again and everyone said, "functional programming is the bees knees! [don't mind these strange hooks that inject side-effects and state]". Then they said, why are we storing state in these pure functional entities. Let's separate out the state and the control..
I think this entire thread has gone of the rails with the local/global discussion. You can have your entire state captured as one 'entity' without every control inside the state being global. The controls can be in isolation, and has nothing to do with the 'state' of the entire page as a whole. Or can break it down into substates if desired, but it doesn't mean each component is global to make that happen.
Sure, that makes sense in a Redux app where you can use FP techniques as you see fit. How do you do that in something strictly functional like Elm? As I understand it 'local state' or a component handling messages locally is not really a thing there.
I am using elmish, which I think is similar enough: every component has its own update method and events it dispatches.The events get wrapped in every parent component until it gets to the root, there it gets unwrapped and passed to the appropiate child update method. At any point, you can intercept the event/update.
(Each component consists of a view, a model and an update function, the model contains wrapped versions of the children models and dispatched updates get passed into the children updates)
It's the broadest level at which two elements can affect each other.
Classic example: if you have a notification bubble near the top of the page, and a notification gets created by some component hidden deep inside the app structure, that message can't be handled in a local sub-model; it must travel all the way to the root node to update the notification bubble stack in the main model.
(Which is why nowadays I prefer to skip the nesting and just have a flat list of all messages in the app. With good spacing and naming, it's quite maintainable and just as solid.)
Nice, but it does not look practical considering it appears to be replacing the whole DOM with every update. However, thumbs up on the idea of UI components that aren’t implemented as a framework, but rather as a convention that different frameworks could support.
It would be so nice to just have a way to specify which part of the markup is owned by which component, and the basic life cycle events they need to agree on to work together, but then allow the internal considerations of each component to be handled by any framework or even plain JS if you prefer.
I’m actually working on something like that, but it isn’t a framework necessarily.
I’ve described it as a “programming language for designers”. The idea is to allow designers to specify the graphical layer of apps, without specifying any behavior.
The core language itself is platform-agnostic, with platform-specific dialects. So you could use it to spec out a web/iOS/android/etc app.
And the cool thing about it is that it compiles to an intermediate representation, which will be a JSON data structure. So you could use it to generate a React component library, or Vue, or Angular, or web components, etc etc.
Not sure I see how. Components appear to return DOM nodes, but as far as I can see they’re not provided an existing DOM structure to inspect. So they can’t be sure how to safely reuse existing DOM, as they don’t control what the parent will do with the nodes they return.
I think I misunderstood what you’re trying to do, in that case. This is a pattern for how to handle state updates, rather than a framework that happens to not have any code.
This is not serious, right? It's a no-framework framework (what?) to build purely-functional UIs using pure-ish (what?) components. The "why" section doesn't answer the question of "why" though - it briefly mentions Redux and useState limitations without explaining how this is going to be a better solution.
Really, how is this different from a top-level useState call, that then gets passed down via props drilldown to children components? The repo mentions that the "heart" is not a code but a convention, but you can do the same convention in React. In fact I believe you can do much better with context - prop drilldown absolutely sucks when the complexity of your component tree grows.
Yes, you can use the same convention in React (or rather use React with the same convention), this is mentioned in the description actually.
As far as "prop drilling" goes, I never understood what is the problem that some people have with it.
If you just put your state in one object its just one more param that you have to pass to components. Do we really need a big-ass framework just because of one extra param.
Also, by passing state explicitly, you get a clear visibility over which component needs what. And it also allows you to restrict which component uses which parts of the state.
If this convention can be used in React, what is the "no-framework framework"? What's the point?
React is not "just one extra param". One thing it does and your "no-framework framework" does not is figuring out what needs to be updated when the state changes. Add some console.log statements to your components and you'll see that clicking on any button on the demo page results in all components being updated, causing update of DOM nodes. How can this possible work in a complex web page? I click on the "Close Modal" button, and every single DOM node on the page gets updated, from the menu bar down to each and every button?
That's the very basic thing that React does. I am not talking about anything else, like component lifecycle or hooks. This not-framework doesn't even begin to approach what React does. If you don't want the "big-ass framework" for whatever reason, there are Inferno and Preact already. Both are great projects and have all the things a developer expects from React replacement.
> If this convention can be used in React, what is the "no-framework framework"? What's the point?
I think the point is a "no-state handling framework". It seems like you can combine this with something like morphdom to get React-like merging for pure DOM updates, and the state-handling is via this hierarchical approach. Or your DOM construction can be via a vDOM library which then handles the merges for you.
I also used the phrase "not serious" on Lobsters. Sorry to the author, but this doesn't meet the bar to talk about outside of a small Mastodon circle. It's just a half-baked idea. It's cool and everything has to start somewhere, but come back to us when you've actually figured something out and made something really fleshed out.
First line on the README says "The no-framework framework for building component-based purely-functional UIs.", So I guess it's "purely-functional" but put backwards for some reason?
Neat proof of concept. I think what you'd want to do is have some form of dom vs component diffing, and traverse the old dom and only create new elements if you find a node type mismatch.
Consider this, you have a slider input, and oninput, you update the state, which creates a new slider input, which causes your mouse drag to get invalidated.
Another consideration - a textarea where you update state each keystroke; will that reset the cursor or have unintended consequences?
Imho a language similar to the combo Dart and Flutter (which is pretty similar to this project) would be perfect to replace all the HTML, CSS and JS. Unfortunately, the former has a terrible web support, but a completely new language that implements styling like Flutter could literally be a game-changer in frontend
I always find that if I want to write an app in the Elm style (or with Redux), I have to traverse up the tree every time I am working on a leaf node. Each input field in a form should not necessarily cause me to have to rework everything up to the root node right? Am I doing it wrong, or am I just missing what benefits this approach brings to offset this extra development cost?