Hacker Newsnew | past | comments | ask | show | jobs | submit | b4ckup's commentslogin

I never get this take. A react component is not just a function, it's a function plus a magically injected context that is accessed through hooks which requires all kinds of guarantees that you have to be aware of otherwise it will have hard to debug consequences. Imo it's anything but elegant. I did projects in all major frameworks and am building a huge angular web app currently. In angular a component is represented as a class plus template (plus styles). A event listener is mostly calling a method on the class. A state can be as simple as a property on the class. It's very natural and there are way less caveats (although not zero).


React uses an algebraic effectful function model which is elegant once one understands it: https://overreacted.io/algebraic-effects-for-the-rest-of-us/


So it makes sense because there's a fancy name for it? For a moment let's just imagine you are inventing a brand new UI framework. You obviously want to have components in it. So how do you represent a component in your new framework? A component needs state, logic and a way to render that state. Do you choose to represent the component as a class which naturally encapsulates state as properties and logic as methods or do you choose to represent components as functions which lack state so you bolt it on via an implicitly injected context that you access via abstractions?


Read into how OCaml 5 does it and you'll have your answer.


> I never get this take. A react component is not just a function,

Exactly.

I did a somewhat longer writeup a while back.

https://blog.metaobject.com/2018/12/uis-are-not-pure-functio...

The pull request is still open :-)


Interesting that you still stand by that, even after Apple moved to the exact same model with Swift UI.

Narrowmindedly worrying about syntactical differences is contributing nothing to the conversation. The point is relinquishing control of state to the framework (be it via props, hooks or @State), and drawing the UI as a pure representation of whatever the framework tells you. Hence ui = f(state). This gets you a metric ton of advantages, which is why every modern framework is doing it.

Classes, by themselves, are inadequate as containers for state unless that state must only exist in memory and never be observed, synchronized or serialized. You can attempt to patch that with decorators, ORMs or whatever, but now you're doing the same thing as React is doing with functions.


Interesting that you would think Apple introducing Swift UI would have any bearing on the correctness of that blog post.

Why do you think it would?

Did you misread my post as "ha ha, Apple does it differently and therefore react is wrong"?

If so, you certainly misread it a lot, and you have the wrong person. I have tons of posts about Apple getting things wrong.

Anyway, did you miss the following part?

I also think that despite all the flaws, react.js and react.native are currently eating native development's lunch.

Clearly I made the point in my post that this approach has a lot of mindspace, despite the obvious flaws, so not sure how you pointing out that this approach has a lot of mindspace invalidates my post.

> Hence ui = f(state).

Every UI is always some mapping of the state. Otherwise it isn't really a UI, is it? What would it be, in your opinion, if it didn't map the state?

> pure representation

What does "pure representation" mean to you? I covered in the post that it sure as hell isn't a pure function of the state. And cannot be.

Did you miss the part where David Abramov conceded that point?

To elaborate a bit, React components aren’t always “pure” in strict FP sense of the word. They’re also not always functions (although we’re adding a stateful function API as a preferred alternative to classes soon). Support for local state and side effects is absolutely a core feature of React components and not something we avoid for “purity”.

> This [ui=f(state)] gets you a metric ton of advantages,

Well, yes. Like being a working UI, for example, which is why MVC is also structured this way.

But can you elaborate the specific advantages you believe the react approach gives us over, say, MVC?

The post elaborates that it would be really nice if UI were a pure function of the state. But it just isn't. And trying to pretend that it is might seemingly buy you some of those advantages, but at a huge cost.


Maybe it's a me-thing, but when I see the creators of a system I trust basically deprecate it, then I try to re-evaluate my viewpoint. Also, when I read the post a few years back, I honestly thought that it must have been a product of its time.

> Every UI is always some mapping of the state.

Sure, but it previously wasn't described as such. It was described as a list of imperative operations "if x do that" (unless the developer just gave up and had a giant refreshEverything() function). IIRC, at the time, MVC had a common problem of controller bloat, precisely because it was trying to perform the reconciliation between view and model imperatively rather than simply describing it as a function. MVVM solved this partially with data-binding, but depending on the framework, you still had lackluster handling of derived state inside the view-model.

> What does "pure representation" mean to you?

I mean that, the render function of the component is a 100% pure function of the state that the framework injects. By "render function" I mean everything except the statements beginning with `use...`. Those are just React's syntax for defining the component. Another framework such as SwiftUI might have defined them outside the function.

> But can you elaborate the specific advantages you believe the react approach gives us over, say, MVC?

There are so many resources on this, so I don't know what I can say to convince you, but I'll try:

* The Compiler. Regardless of whether you think it’s self-inflicted complexity (I don’t), functional patterns generally are easier to statically analyze and transform.

* Transitions, concurrent rendering, suspense, & time-slicing. All of these are possible by rendering components with outdated state. A low priority update may trigger a loading state and defer its commit. Meanwhile, high priority updates can continue to work as usual. In the past ~2 years, this is easily where I've seen the most UX & DX gains in frontend.

* Most importantly: readability. Even if components are only 90% pure, I still see side-effects and state clearly marked. Even in MVVM, I've seen so much spaghetti from my coworkers. In React & post-React frameworks, when debugging a component, I have a much narrower range of things I need to check. For example, I don't have to worry that an object I'm reading from is being mutated by a component on a completely different route.

Overall, the reason why this post rubs me the wrong way, is that you took a theoretical design document, misunderstood it for the actual, practical implementation and snarked at the authors for not going with the "obviously correct" solution of OOP. Not seeing the bigger picture in 2018 is understandable, but now it's... interesting.


> but when I see the creators of a system I trust basically deprecate it,

What makes you think I trust Apple? So yes, that's very much a "you thing".

And SwiftUI is laughably bad. And my very early criticisms of Swift, for example, have panned out precisely as I predicted.

> > Every UI is always some mapping of the state.

> but it previously wasn't described as such.

Yes it was. Except this was seen as the obvious given that it is. Because, once again, a UI that is not a function (mapping) of the model is not a UI.

"In Smalltalk-80, a view is just a visual representation of a model" -- https://en.wikipedia.org/wiki/Model–view–controller#View

> IIRC, at the time, MVC had a common problem of controller bloat,

Nope. Non-MVC implementations had the problem of controller bloat, because they didn't actually implement MVC.

> the render function of the component is a 100% pure function of the state that the framework injects.

Except, as I've correctly pointed out: it's not.

[Advantages]

None of this is in any way specific ("The compiler". Seriously?) or clearly an advantage that can be tied to this type of framework. So yes: you're not even close to convincing me. Because there's no "there" there.

> the reason why this post rubs me the wrong way, is that you took a theoretical design document, misunderstood it for the actual, practical implementation

You misunderstood the post. Completely. The document claims "pure function". This is laughably false. The question is what is left when you remove "pure" from "pure function". And the answer to that is: nothing.

That doesn't mean there are no benefits, but the benefits cannot be "what you get from being a 100% pure function", because it ain't.

Just like the benefit of butter can't be "it's 100% fat free". Because it ain't.

And if you keep insisting that those are the benefits, then I don't know how to help you.

And again, it doesn't mean there are no benefits, but they are both smaller than and quite different from what you claim. And with the benefit being fairly small, the other question is what the cost is of pretending this is so when it is not. And the answer is: pretty high.

And it's funny that on the one hand you go with the same "well, you're taking the "100% pure" thing too literally", when just a few lines above, you yourself made "100% pure function" the defining characteristic.

So which is it? Make up your mind. It appears to be Schröding-important.

Any UI that actually is a UI is some sort of function of the state. Otherwise it is not a UI but random graphics and/or decoration.


Maybe you would prefer React's class-based syntax. It's still there if you want to use it


I actually do and my critique is directed at function components which seems to be the standard nowadays.


Could you elaborate why you dislike lifecycle methods? I read this take a lot and I use mainly angular but did some smaller projects with react class components and with function components. I also think function components are very counter intuitive but I also never had anything against lifecycle methods.


They often require quite complex ifology for simple use cases. Also didmount and diduptade often needs to be overriden together only to have almost the same implementation. They also have some gotchas regarding state updating inside them.


I'd say on average about 50% faster but it really depends on the task at hand. On problems that can be isolated pretty well like a new feature that is relatively isolated (for example building a file export in a specific format) it's easily a 10x speed up. One thing that generally gets less talked about is exploration of the solution space during manual implementation. I work in a very small company and we build a custom ERP solution. Our development process is very stripped down (a good thing IMO). Often times when we get new requirements we brain storm and make a rough design. Then I try implement it and during that phase new questions and edge cases arise, and at any time this happens we adjust the design. In my opinion this is very productive as the details of the design are worked out when I already know the related code very well as I already got down to implementing. This leads to a better fitting design and implementation. Unfortunately this exploration workflow is incompatible with llms if you use them to do the implementation for you. Which means that you have put more effort in the design up front. From my experience that means the gain in speed in such task is nullified and also results in code that fits worse into the rest of the codebase.


That's awesome! I feel similar, I drew a lot back in the days because growing up in a small town I was bored so often. I did portrait art only but today I struggle because I just don't know what to draw and I'm just not good at doodling. Best of luck to you!


I once wrote a formatter for powerquery that's still in use today. It's a much simpler language and I took a simpler approach. It was a really fun problem to solve.


I tried to use toml in as config format for the app I am building at my day job. I ditched it for json because it's representation is not unambiguous, meaning the same object tree has many many different valid representations in toml. This makes it really hard to implement roundtripping of the config string to object tree and then back to config string without losing the specific toml representation chosen by the config author and no library that I've encountered supports it properly. For me this was a very important use case (config migrations). I implemented my own json parser that preserves json formatting and comments in half a day. Maybe json is harder to read and write but imo it's simplicity is a good feature.


I think you meant JSON5 since JSON doesn't have comments.


Douglas Crockford himself recommended using comments if you like then piping it through JSMin. Unfortunately the original post on Google+ no longer exists but it's referenced in a HN thread[0].

    I removed comments from JSON because I saw people were using them to hold parsing directives, a practice which would have
    destroyed interoperability. I know that the lack of comments makes some people sad, but it shouldn’t.

    Suppose you are using JSON to keep configuration files, which you would like to annotate. Go ahead and insert all 
    the comments you like. Then pipe it through JSMin before handing it to your JSON parser.
Which of course doesn't help because you could still just add parsing directives into the comments anyway. But as far as I'm concerned that means the spec implicitly allows comments as long as they're stripped out in transport.

[0]https://news.ycombinator.com/item?id=3912149


It doesn't matter that if he allowed comments initially if the final (current) specification didn't allow them.


Well since it's my own parser I support both inline and line ending comments. So I guess it's technically jsonc (json with comments) but whatever really.

Clarification: when speaking of json formatting I handle 2 distinct cases that make sense for me: inline objects and inline arrays (where all properties/ elements are on the same line) which make Configs more readable when the objects / arrays are small.


Really interesting! I'm very much interested in pychedelic graphics. I played around with shadertoy a little bit maybe I should give it another go. For anyone interested I made some cool visuals by interpolating prompts in stable diffusion 1.5 like https://m.youtube.com/watch?v=ajfMlJuDswc. I found that the older diffusion models are better for abstract graphics as it looks more "raw" and creative.


This is mostly how I indent my code. I don't know why so many people hate it. We have huge screens and spacing conveys structure so I use spacing when appropriate, like a ')' in its own line. I work in a *very* small team though and I write most of the code.


This sounds like a good use case for using a service worker. All tabs talk to the service worker and the worker is the single instance that talks to the backend and can use only one connection. Maybe there are some trade offs for using SSE in web workers, I'm not sure.


BroadcastChannel is a better solution for a couple of reasons. Service Workers are better at intercepting network requests and returning items from a cache, there’s some amount of additional effort to do work outside of that. The other thing is they’re a little more difficult to set up. A broadcast channel can be handled in a couple lines of code, easily debuggable as they run on the main thread, and they’re more suited to the purpose.


Weblocks (https://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_A...) are an even better way to do this than Broadcast Channel


I disagree. You can just postMessage to communicate with the service worker and therefore I imagine the code using broadcast channel to be actually quite similar. About debugging, service workers are easily debuggable, though not on the main thread as you already mentioned.


agreed. Workers was one of my first thoughts but I think BroadcastChannel delivers with much lower LOE


I use vscode (with omnisharp not c# devkit) for c# every day. Did you try it out?


I did not! Rider is extremely satisfying to use.


Is devkit better than Rider ?


I tried to use vscode c# devkit but it is horribly unstable and has severe bugs that make it unusable for my projects. But I'm really happy with vscode + omnisharp. I never used rider so I cannot really say which is better but I tend to not like jetbrains IDEs (from experience with IntelliJ and webstorm).


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

Search: