I love React Hooks(vijayt.com) |
I love React Hooks(vijayt.com) |
Everything I tried before it (jQuery, Backbone, Knockout, Angular, Meteor (with Handlebars)) felt like it fell short or, in the case of the databinding-oriented ones, like a broken abstraction. I get a similar feeling when looking at Vue though I have no experience so I might be wrong.
I too am a bit skeptical about hooks making what looks like pure functions act like stateful ones. I am not using hooks yet but besides from Dan Abramovs excellent articles about their rationale, I think I will look at them like a new paradigm, only using a syntax that we know from something else. In fact, I wouldn't be surprised if I some time in the future will be using React to write state machines for something that doesn't have anything to do with UI, where "rendering" composes state related to something else entirely. I could see hooks being a game changer here.
Progressing down Vue, you realize how they have tried to prioritize convenience. For example, using "v-on:keyup.enter" you can map an action to "Enter" key without writing code for handling that key.
I liked the React's approach but it seems its focus is on purity of abstractions than convenience. Don't even get me started on Redux which is epitome of needless complexity—containers, reducers, event emitters? Was all that really needed?
Note: I have no idea how Vue fares when code base is huge, but my intial impression makes me feel it's far better choice than React.
[1]: https://vuejs.org/v2/guide/#Declarative-Rendering [2]: https://reactjs.org/tutorial/tutorial.html
Thanks for feedback!
The linked React guide is intended to be a pretty comprehensive tutorial — not a getting started guide in the same sense. I wouldn’t say they’re comparable in how much about either of them teaches you about using a library. Maybe it’s not obvious from the wording.
If you do want a simple “getting started” guide that doesn’t require any tools, it’s right here:
https://reactjs.org/docs/add-react-to-a-website.html
And you can progressively learn all important concepts starting from here:
https://reactjs.org/docs/hello-world.html
Another common destination is this guide, which matches the Vue one in purpose a bit more closely: https://reactjs.org/docs/thinking-in-react.html
The “get started” link on the React page links to resources for people with different experience levels:
https://reactjs.org/docs/getting-started.html
Hope that helps!
My biggest problem with Vue is the template syntax. Since JSX is a thin layer over Javascript, few modifications have to be done over Javascript (or Typescript) tools to make them work with JSX (or TSX). Vue templates are a totally new language which requires more complex tools. I've never had any problem using refactoring tools (renaming variables, go to declaration, find usages, ...) with React, while in my last Vue project, renaming a variable broke code.
Vue has Vuetify, which has been a breeze to use, though. I don't know if there is a React equivalent.
I completely agree that it’s the best thing that has happened to web UI programming in recent memory, but for me, personally, I think Qt’s QML is the best thing that has happened to UI programming in general in recentish years. I like using react, especially from clojurescript using re-frame and I’m very thankful that it exists, but QML has been some of the most pleasant complex UI development I’ve done in the last few years. Now, if only Qt were more like re-frame, then I’d be super happy, but I love the declarative nature of QML and the anchor-based layouts.
What’s wrong with that? Any conceivable application needs to actually have state that changes over time. That’s true of all software written in a purely functional style.
By definition, any software that is purely functional does not have explicit mutable state. In practice, it is often useful to have parts of a system written in a pure functional style but other parts that do use mutable state, either explicitly or via some mechanism that simulates it in a functional context.
Of all these I have used jQuery and React, but I prefer plain vanilla over these. No breaking changes, no hype cycle, excellent documentation and with good old design patterns any complex problem is easily solvable. Believe it or not, but managing state is dead simple with just vanilla javascript.
Keeping state and the view in sync, however, is not. For example, if you have a list of TODO's that the user can edit in the browser, and that you want to be able to send to the back-end, every time the user adds a TODO, you'll have to remember to update both the model and the DOM. Likewise after an edit or deletion.
These tools really do solve a problem.
- Magic, in the unfavorable sense: if hooks were implemented in an indepedent library, just hearing that they "must be called in the same order every time" and "cannot be used inside conditional statements" should make anyone wary.
- Scope creep: if anything, I wish React focused on reducing its size and API surface.
- Entanglement: related to the point above, the goals of hooks would have been better served with a separate, tiny library that doesn't need to know anything about React, and usable anywhere else, with plain functions that can be tested or reused independently.
Well, the topic deserves a deeper criticism than "it feels wrong", so I hope someone can write a worthy article called "Why I Do Not Love React Hooks", with an example of a better, alternative solution.
I hesitate to bring up a cliché, but it's starting to feel like React is the new jQuery. I'm already trying to anticipate what comes after React, in which case I want my code to depend on the smallest possible API surface area.
But then again, maybe it's my wishful thinking that we would move towards "universal components" (using dependency injection to pass in React or other view renderers like Web Components). Since much of the JS ecosystem seems to be going "all in" on React, perhaps I should surrender to its current. As long as I continue to use React, it looks like there's no escape from its hooks..
EDIT: I should add that the above is just my opinion at the moment, and I'm open to changing my mind. Who knows, I may unwillingly start using them (since everyone else seems to be), and come to love hooks after all.
The real issue which I want to see solved is getting people to remove business logic from React. I see components loaded to the gills with data fetching and overly complicated async rendering schemes. Personally I try to keep my React components extremely dumb. Instead I try to keep most of the business logic on the server side when possible, and in Redux otherwise. But even that's not great. Redux is fundamentally a data store, not a business logic library. Trying to do complicated logic with selectors/actions is a nightmare. I suppose that's why front end frameworks like Angular and Ember are popular. React ultimately is a view library and yet it provides no good option for the business logic.
Hooks are great for this. You extract all business logic into custom hooks and your components are left as dumb renderers calling other functions to get values. It’s great.
The entire paradigm of React keeps changing as each pervious iteration proves to be “messy” or “over complicated.” createClass? Nah that’s obsolete. Mixins and HOC - oh wait, bad idea, hooks to the rescue!
At what point do people start to call BS and say you shouldn’t build around a framework that needs to be reinvented every year or two?
Recently i was assigned a PR for a component (a login form) i wrote about a two years ago which was a whole 300 lines. The person who wrote the PR also took the time to make it "functional", which has now resulted in it being split into almost a dozen different files. I don't find this cleaner or easier to understand at all.
Current team i am on uses MobX, and Typescript for our app and frankly it is painfully simple, and yet people keep arguing that we should drop mobx, and switch to hooks and i don't see any benefit.
And if you ever had to deal with correctly typing HOCs or render props you had to dig very deep into conditional/mapped types in TS. With hooks this is basically gone.
I think hooks might be nice for data fetching when it comes to TS as it will super easy to get typing.
I'm still not convinced by hooks though.
With Hooks, the auto-patching goes away, so your call to setMyCustomState() always requires an argument of type TState.
There are similar issues if you use the 'static defaultProps = { ... }' on a class - you have to manually specify the type of defaultProps - often it is Partial<TProps>
Yep. Now there are four.
I have no specific opinion about React hooks (or about love for that matter), but “languages” with a simpler vocabulary do tend to have an advantage in the long run.
You get warnings in jest about needing to use act from react-test-renderer if you use async code to trigger state updates - the solution being recommended currently is mock every promise with a synchronous version, which then litters your app code with conditionals in many places for whether to use the mock or real promises. At that point, you're much better off using Angular for writing decent component/unit tests, where you don't have to fight with any async DOM or JS api in order to write working tests, or pollute app code with test specific branching logic since that is all handled at a single injection point via the IoC container.
If you have promises, you're forced to bleed a isMounted type of flag into the cleanup function scope in order to guard against promises attempting to trigger state changes after the promise is complete with its async function (i.e. data fetching).
These are two frustratingly painful dev ergnomoics situations that are unsolved with hooks. Otherwise, I am happy with them, but these are major pain points I have encountered with them so far, and given FB doesn't use promises in their internal apps for the most part, I don't see them likely to put in much work solving these problems unfortunately.
Disclaimer: I would love to put in some effort to solve these pain points with design discussions & code, but unfortunately I cannot put in that work without going through approval processes with 5+ people.
This is inaccurate.
The first problem has an issue tracking it (https://github.com/facebook/react/issues/14769) and even a pull request (https://github.com/facebook/react/pull/14853). It’s barely been two weeks since the first release and we’ve been focusing on fixing actual bugs as soon as possible. As I hope you can understand, warnings in tests are a bit less critical and can wait behind production bugs. But we’ll get back to fixing the warnings as soon as possible — maybe even this week.
As for isMounted-like flag. This has nothing to do with Hooks. Classes need exactly the same thing. If you forget it, you’ll likely have both the same kind of warning, and possible race conditions from requests arriving out of order. In longer term we’ll offer a much simpler data fetching integration (read about Suspense) which doesn’t involve effects or lifecycles at all. I think you’ll like it.
You may find Dan’s thread on this subject interesting though — he tries to explain why neither plain classes nor plain functions are the best fit for React: https://twitter.com/dan_abramov/status/1093694465917751298.
People who wish that progress would stop on jQuery & Rails - won't like React Hooks either.
People keep trying to fix them: https://github.com/andreypopp/autobind-decorator
With a class instance, what happens if you need to bail out of a render and potentially restart it again later? The developer could have done literally anything to their class instance the first time through. They could be inheriting from anything and doing whatever they want to `this`. You can't easily "restart" it from its original state, unless you made a perfect snapshot, which is not easy with class instances – you'd need to perfectly deep clone the prototype chain and such.
With functions and hooks on the other hand, there is no class instance or prototype chain to worry about. All state (whether stored via useRef or useState) is controlled by React – the actual object it gets stored on is hidden from the developer. If React wants to ditch the "instance" it was updating on the previous attempt and reuse the one it started with, it can do that without worry.
It's the same reason "time travel" features are easier with more functional approaches. Adhering to functional programming ideas pays off in the long run.
Longer comment: https://news.ycombinator.com/item?id=19206401
In my professional opinion, which is based on years spending time with react, the typical gotchas in this framework are down to experience. Experienced react, and more importantly js, developers will write better, more performant code. This is applicable across the board regardless of the framework/language. Hooks will not particularly remove this need nor will make you a better programmer.
While hooks look functionally ok what worries me is that they will be subject to a number of problems. For example, complex hooks/components might be subject to memory leaks. With hooks, we are defining closures inside the functional component which will be subject to having access to proceeding scopes. This is an anti-pattern that we removed from our code-base by using classes. The second problem is that your component will needlessly re-render in those cases where the component is not entirely functional. This may not seem like a problem in the simple examples seen thus far, but it will be with more complex components as I've seen in my experience.
React is one of the best frameworks we have seen around so I am happy that we keep pushing the boundaries but what worries is me is that the React team seems to declare that they are moving towards components written with hooks (not removing classes) which in my opinion is not based on solid evidence that will amount to anything useful in particular.
Again, as far as I am concerned, hooks does not contribute to anything that we are not solving in much better way and I doubt they will ever be used at all as far as our code-based is concerned.
Additional reading: https://reactjs.org/docs/hooks-faq.html#are-hooks-slow-becau....
If you haven’t seen usehooks.com check it out.
Here is a compelling example of combining a few hooks together for an elegant solution:
>However, there are times when we need to pass an extra parameter. In those cases, we cannot use bind because we cannot use bind with arrow functions.
But you can pass the extra argument to the arrow function directly: `onChange={handleChange('name')}`. And use it as:
handleChange = (field) => (e) => {
this.setState({ [field]: e.target.value });
}
Sure it still has the problems of arrow functions I think the arguments against it were worded poorly.This sounds like a totally BS reason in the context where it is said.
Two things stand out about hooks to me (from what I have read, have not used them yet):
1: well suited to writing functions rather than classes - this is appealing because there is a line of thinking that values function composition over object orientation.
2: it sounds this finally solves one of the major challenges in react which is simple cross cutting. Cross cutting was always painful and I'll be very happy if this is cleanly solved.
I'm hesitant about new functionality that increases complexity, or is harder to understand and grasp. I'm very enthused about anything that goes the other way.... the industry must constantly strive for simpler ways to do everything.
For me simplicity is the three C:
Clarity, in terms of how many concepts do I need to know to understand given some lines of code. The fewer the better.
Coherence, how similar is the expressions I write to what I want to say in terms of the given language. The more similar the better.
Confound, how surprising is the behavior of the code? the less the better.
The issue with hooks I think is that they're trying to treat symptoms rather than solve the problem, if you read the original motivation document by Dan, it talks about State Logic Reuse, Complex Components and People Don't Understand Classes; I think these problems can be tackled much better by their own without trying to add more APIs to React or taking drastic measures like completely change the way people think about React components.
I don't understand this comparison. jQuery extended the existing DOM API to make it more user friendly and made it cross browser compatible (an incredible thing in it's age). React does nothing like this - it brings a completely different concept to designing user interfaces that has nothing to do with the DOM api.
If anything, I see hooks as a response to the community that was installing React+Redux(mobx/whatever global state manager library is flavor of the week) by default. This feature makes it possible to use React as more of a one stop solution, which I definitely welcome.
> I'm already trying to anticipate what comes after React, in which case I want my code to depend on the smallest possible API surface area.
That's a fools errand. The code I wrote 10 years ago that relies on jQuery still relies on jQuery (and guess what -- it still works the same as it did when I wrote it!). And the code I wrote 5 years ago that relies on angular1 is still in production (and guess what -- it's fast and incredibly bug free because it's had so long to work out the kinks). Despite these frameworks no longer being fashionable, they still serve in production environments fantastically.
You don't have to rewrite your user interface code just because something else came along. You can embrace the positives of the library or framework that was being used at the time you wrote that code and create a rock solid application. Your goal shouldn't be to write code that depends on the smallest API surface because good code that correctly uses a well written API (which both jQuery and react are) will not be hard to maintain down the road regardless.
2. Don't hooks remove the need for redux, etc.? Meaning, don't hooks radically reduce the amount of libraries you need to know about?
3. I prefer to use pure React and not have to choose between Redux, Flux, Mobx etc. And, then do I need to use redux-thunk, etc?
I actually really like the progression towards hooks. I think the articles from the core team (like Dan Abramov) have been well written, explaining not just the how but the why, and it feels like hooks serve to make things simpler and more readable. Yes, you have to throw away a lot of things you spent time learning, but I'm not sad to see anything go away that hooks now handles.
That's true, especially JSX caused an uproar in the beginning as "too much magic", and then was gradually accepted as a vast improvement to previous/other ways of templating.
> Don't hooks radically reduce the amount of libraries you need to know?
I'm really hoping so! If they do indeed "serve to make things simpler and more readable", it would be a net positive, regardless of any initial misgivings and possible effort to migrate.
This is a common first criticism. There isn’t much magic going on implementation-wise (you could probably implement a simple version of Hooks yourself in <200 lines).
The static call order is controversial. But I strongly encourage you to play with it before forming a final opinion. Pretty much everyone who loves it now hated it at first. (I’m not an exception to that.)
It’s not even as much a technical limitation (we could make arbitrary order work) as confusing semantics if you remove it (how can state be conditional?).
So static call order seems like something you’d enforce with a linter anyway. At that point the cost of allowing dynamic call order becomes not worth it. (Both in API and runtime overhead.) I wrote about it here: https://overreacted.io/react-as-a-ui-runtime/#static-use-ord...
Magic is bad when it’s confusing to use or debug. There are some challenging aspects in using Hooks (like in any programming model, there are cases made easier and cases made harder) but the static call order is not one of them in practice.
>Scope creep: if anything, I wish React focused on reducing its size and API surface.
Regarding file size, ironically, Hooks can decrease the overall app file size because function calls minify better (more things can be mangled). The implementation itself makes up for less than 4% of React.
We’re working on making it smaller — but there’s a balance between size, runtime performance and providing abstractions that help remove application and other library code (usually much more impactful). Numerous libraries that migrated to Hooks reported savings in size.
>the goals of hooks would have been better served with a separate, tiny library that doesn't need to know anything about React, and usable anywhere else, with plain functions that can be tested or reused independently.
Regarding API surface and the notion of what should and shouldn’t be in React, you might think about it differently if you think about React API from first principles.
Here’s a longread you might find interesting that talks through 90% of React on one page, including Hooks. https://overreacted.io/react-as-a-ui-runtime/
Cheers.
> you could probably implement a simple version of Hooks yourself in <200 lines
It reminds me of the Egghead video course in which you described "how to write your own Redux". That was a great explanation of the paradigm, and transformed how I think about state management in an application.
What I love about the concepts behind the paradigm, is that they can be implemented (as they are in Redux and elsewhere) as a handful of tiny functions that work with or without React, for composable and reusable state and actions.
I think my hesitation about Hooks as they're implemented, is that it seems to go against the ideal of de-coupled, pure functions. Although it does encourage that for the users of hooks, its own implementation feels coupled and impure.
For example, people are applying the Flux/Redux paradigm outside of React components and the UI/views layer, like server-side or independent features that need to manage their own states. I wish that Hooks had taken a similar approach to Redux, as a canonical approach to a generic and generally applicable paradigm, where one could "write your own Hooks".
> I strongly encourage you to play with it before forming a final opinion. Pretty much everyone who loves it now hated it at first. (I’m not an exception to that.)
Yes, I'll keep an open mind and study it more.
I read "React as a UI Runtime" when it was published, and it was insightful (will read it again to really digest it). I do love the concepts and principles on which React has been built, so I'll try to understand the reasonings behind how/why Hooks were implemented the way they are.
It's more complex but doesn't resort to the impure functions like hooks which cause the same order/conditionals rules.
https://paulgray.net/an-alternative-design-for-hooks/
I think the next big framework will build on top of the declarative jsx-style rendering from react, while also providing pure abstractions of the side-effecting browser APIs
Happy to elaborate on specific points. (This is a very condensed summary.)
A slightly longer version that requires less context: https://medium.com/@dan_abramov/making-sense-of-react-hooks-...
It’s rather reasonable for them to be excited about a new version that keeps (or improves!) the good parts while having fewer tradeoffs.
- Vanilla JS: it works, but holy moly it looks bad and the amount of code I have to write to do even basic stuff really really hurts my brain. (Actually what am I talking about, it never got close to "working" before I moved on to...)
- jQuery/Node: ooh, this is better. But still, doing stuff takes ages.
- React: OH MY GOD WHAT IS THIS HEAVEN.
People will say that "people like me" shouldn't be writing web apps if we don't know what we're doing. To them I say, screw you. These tools enable us to do things that would never have been possible.
Thank you from the bottom of my heart for doing whatever it is that you did. :-)
Of course React, like any library/framework, is going to have its own idiosyncrasies. That isn't the question. The question is if it's still better than alternatives, and people clearly seem to think so. My first React app I ever made years ago still works on the latest React, seems pretty stable as far as the web client ecosystem goes.
Client development isn't trivial on any platform, btw. But I think we have it pretty damn good on the web, relatively.
I see a good possibility with WebComponents, which React seems to be the only framework not going for them.
These pattern changes are tiny improvements. Basically they are improving the syntax a bit.
For one, react is a fairly competently done, roughly MVC UI framework. The components are views, render() is drawRect. Being in the browser, render() doesn’t draw into a bitmap, but rather returns structured objects.
That also means painting optimization is diff-based rather than damage-rect based.
Which brings us to what appears to be the biggest difference: traditional MVC GUI toolkits such as Cocoa clearly separate creating a UI from updating the UI with data. For updating the UI from the model (and the model from the UI), you follow MVC, which specifies how the Views map the model to the display and vice versa.
The actual views stay the same during that time, the data changes.
React combines these two steps into one, conceptually recreating the entire UI at each step like a game.
While this solves some issues that have crept into toolkit programming due to a shift towards handling dynamic aspects via changes in the view/widget hierarchy, it is conceptually rather muddled[1].
This conceptual muddle, claiming that the UI is a “pure” function of the state when it is clearly not, seems to the major source of those problems that keep needing to be solved.
To me it would seem that looking dispassionately at the problems react solves without the conceptually troublesome baggage might be useful, but that’s just my € 0.02.
[1] https://blog.metaobject.com/2018/12/uis-are-not-pure-functio...
I think the crux of the issue is here: > "So if we don't make the incorrect assumption that UIs are unstable (pure functions of model), then we don't have to expend additional and fragile effort to re-create that necessary stability."
In Cocoa, and generally in desktop UIs, your assumption is true. A UI is a set of "slots" into which dynamic data is displayed. But on the web this is a lot more fluid. You can have visibility toggles across the application, and the UI can vary drastically between one state to another. I think this is the fundamental mismatch between the object-oriented approach to UI and the functional approach to UI.
Also, in the "Lists" section, the functional approach would not be to create a persistent Map, which then has to be invalidated as its source data changes. Instead, the mental model in the functional approach is to always re-compute everything; memoization is an optimization that should be transparent.
This part is wrong. Your huge components are made of what? Small things. Isolating all those small things just let you add more boilerplate and mental load when trying to debug. To reduce complexity you have to remove code, not move it around.
The problem i have noticed is that people say "well it works in isolation", but on integration with other components it doesn't work properly. Unfortunately this is a huge problem i find, and frankly the idea of numerous shared hooks and ensuring they are side affect free is very painful.
I'm surprised you find it so hard to comprehend what other people think considering how trivial I think it is to understand them.
Maybe there's a lesson here.
I think you’re confusing it with Google.
>I get the sense the only UI people who really know programming work on the React team
I haven’t worked in many companies before, but I find my colleagues across the company to be very good UI engineers. Not sure where you got that impression.
>I'm a bit dumbfounded about the "this" and "class" confusion concern as well
In the grand scheme of things it’s a pretty minor concern (although people do tend to overfocus on it because it’s easiest to explain and discuss).
The motivation for Hooks is:
* Share reusable stateful and effectful logic between components. Like mixins but without name clashes or the diamond problem. Hooks can be applied more than once, and are instantiated per call.
* Colocate related logic instead of artificially splitting it into lifecycle methods.
* Accurately model component as being in multiple states at the same time for concurrency. (Important for future React features.) Closures can do that because they capture specific props and state.
Finally there are some difficulties related to optimizing class code at compilation time. Such as inlining and fusing classes together. Functions make this simpler and they also minify better due to safer mangling.
All of these motivations can be challenging to explain. So people tend to overfocus on “this”.
I also wrote this, let me know if it helps: https://medium.com/@dan_abramov/making-sense-of-react-hooks-...
> The second problem is that your component will needlessly re-render in those cases where the component is not entirely functional.
is addressed by the react developers in the FAQ [1].
The answer wasn't obvious to me, so I made a toy example in CodeSandbox [2]. There are 3 counters that can be updated using 3 corresponding buttons. Each counter uses a different approach:
1. The "handler" counter uses "useState" + "inner function in the parent's body". The corresponding button rerenders every time the parent rerenders (i.e.: the problem you are highlighting)
2. The "callback" counter uses "useState" + "useCallback" to memoize over the counter's value. The button rerenders only when it is clicked (and hence the counter it controls is updated).
3. The "reducer" counter uses a react context to inject a "dispatch" function that calls an out-of-parent reducer. The button never rerenders. The docs are clearly pushing the reader towards this solution (albeit it is contrived for very simple examples such as this one, I can see the benefits surpassing the boilerplate overhead of reducers in more complex situations).
[1] https://reactjs.org/docs/hooks-faq.html#are-hooks-slow-becau...
I'm currently rewriting my product's rich text editor in SlateJS and hooks and they're making customizing the editor much easier that was possible with class based components.
SlateJS has a concept of plugins that you can pass to the base editor to customize behavior. For example, I can write my own "AutoCapitalize" plugin that will auto-capitalize the first word of each sentence. Or maybe a "Highlighter" plugin that highlights certain key phrases in the text.
Some of these plugins need to read data from my store and/or call actions, and some don't. For the ones that do, I can instantiate the plugin with a hook (e.g. useHighlighterPlugin()), which nicely hides the fact that the plugin is hooked up to my data store / actions.
Why is this useful?
I have about 10 different text editors in the product, and each has a different set of plugins associated with each... I need to be able to mix and match them, reusing some the same plugins over and over.
Maybe one editor has a list of plugins: [autoCapitalizePlugin, highlightPlugin, spellcheckPlugin]
Another might have: [highlightPlugin, readOnlyPlugin].
Without hooks, to hook up these state and action dependent plugins, I would have to have higher order components wrapping each of these editors, each of these HoCs grabbing the different specific data / actions needed to make these plugins work properly, and passing this data explicitly to construct these plugins via props. Very difficult to reuse code this way.
I suppose I could write an HoC for each plugin, but then suddenly I'm wrapping my component in 10 HoCs for 10 plugins. Plus there'd be possibility for props naming collision.
It would have been impossible to both have reusability _and_ brevity without hooks.
Instead, I can just create the plugins I want declaratively using hooks:
const highlighterPlugin = useHighlighterPlugin();
const spellcheckPlugin = useSpellcheckPlugin();
https://medium.com/@dan_abramov/making-sense-of-react-hooks-...
I hadn't thought of the issue in terms of the three C's you've mentioned, but the criteria also seems accurate.
In my opinion, the popular SPA frameworks (Angular, React, Vue, etc) all suffer from similar problems. They build abstractions on top of abstractions, they force you to learn domain-specific languages (e.g., JSX), lots of new concepts to learn before you can be productive, they are fairly opinionated about how your application should be structured, etc.
If you have the time, take a look at this JS framework I put together ( https://github.com/elliotnb/nimbly ) and it's state management dependency ( https://github.com/elliotnb/observable-slim ). I built the framework so developers can take advantage of the benefits of modern frameworks (templating, data binding, state management, no explicit DOM manipulations, automated unit testing, loosely coupled modular components, etc) but without the typical drawbacks of modern frameworks. The framework has far fewer abstractions than React or Vue, requires no domain specific language (i.e., you write in plain HTML, CSS and JS), and does not require compiling/transpiling. The framework embraces the DOM instead of abstracting away from it and still refreshes/re-renders components in a highly performant manner via DocumentFragments.
We've used the framework fairly extensively at my work because it plays very nicely with our jQuery-heavy legacy code and allows for much easier re-factors.
The observer library has gained a fair bit of interest from other developers (~2k monthly downloads via npm) and it'd be great if I could interest others in trying out the framework too. I'd love to hear feedback from anyone who takes the time to try it out. Other contributors would be fantastic.
It’s more about being able to reuse some stateful logic between components. That’s the point of custom Hooks. There are pretty cool libraries existing already. For example React Spring takes advantage of that programming model for animations: https://www.react-spring.io/docs/hooks/use-spring
I tried to explain the motivation for Hooks here:
https://medium.com/@dan_abramov/making-sense-of-react-hooks-...
Hope it helps.
And no, you do not need to remove code to reduce complexity you're mistaking correlation for causation.
Boilerplate may occur in the short term during a refactor to pure functions but that can eventually be refactored out once things are unshackled enough to be refactored.
I find Vue templates slightly cleaner for that reason, but the difference isn't big. How they're used is different, though: React wants everything, including the XHTML, to be javascript. Vue puts it all in HTML, with script tags for the javascript.
<div v-for="item in items">
<span>...</span>
</div>
The refactoring tools must know that the "items" inside the "v-for" refers to a property of the data object. In other words, the content of the data bindings is a totally new language by itself (the content of v-for has its own syntax, with a parser).Compared to the equivalent in React, which would be:
{this.items.map(i => (
<span>...</span>
)}
Or possibly let elements = [];
for (item in this.items) {
elements = <span>...</span>
}
It's way easier for a refactoring tool to support JSX since it's just syntactic sugar over JS. If you were the developer of such a tool, you would just need to consider "<>" as values and possibly consider anything inside "{}" as normal Javascript.And indeed, as pointed by another commenter, React supports classes and integrates very well with Typescript since React 16.
const A = () => <div />
const B = () => <A />
JSX turns that into: const A = () => createElement('div')
const B = () => createElement(A)
That is all that JSX does. Vue on the otherhand parses its own language, breaks scope, separates concerns that shouldn’t be separated and in the end joins them via dependency injection again. We’ve been through this years before Vue existed with angular and others.BTW, your info is outdated. "class" is allowed in React as of V16.
Thanks!
I think your analysis is very insightful, but there are some additional wrinkles. I don't really think it's just OO vs. FP or Desktop vs. Web, though those aspects definitely play a role.
First, if it's an actual User Interface, something that the user interacts with, stability is not something imposed by platform convention or frameworks, but an inherent requirement: if I edit text, my text field (or editor) better be stable as I type, or it will be impossible (and infuriating) to actually interact with. If I interact with a list, that list better be stable. etc.
If it's just (mostly) visualisations that I consume mostly passively, that's a different matter (and then there are games, where you interact with a full-screen visualization).
That's not to deny your observation that interfaces have become more fluid, certainly on mobile and web, and that there isn't a certain kind of desktop application with very static/forms based interfaces (business CRUD...). You can be more static on desktop because you have the screen real estate, and disabled but visible controls are generally considered to be better than things that hide/show/slide.
So there's a bit more going on, and I think a crucial difference is how the more dynamic parts of interfaces are created. After all, it's not as if "classic" user interfaces are incapable of doing dynamic visulations and interfaces: you create a view, and within your view your drawRect: (Cocoa) method draws whatever you want however dynamically you want it. As an extreme example, 3D games tend to have an OpenGLView (now a MetalView) and inside that you have all the action.
After all, "object orientation" has both: data-structures and methods that act on them, and OO user interfaces also have both, meaning you can get as "functional" as you want. You can compose objects, draw procedurally/functionally and mix and match both to your heart's content.
For some reason, or maybe set of reasons, that doesn't seem to happen much any longer. Instead "object oriented" appears to be interpreted more in the way of "object oriented graphics", where you have a set of shapes (or widgets) that you can assemble, but without the part where objects can have arbitrary behaviour.
What this unwillingness or inability to embrace the full capabilities of OO means is that when you have dynamically varying content, you now have to dynamically change the composition of your objects/widgets. Which, admittedly, those frameworks were not created for, I am guessing at least partly because they have a different mechanism for achieving those effects.
> [Lists, functional approach, re-compute ]
If you look at NSTableView and related, you will see that they also provide a fully lazy interface to the data source[1], which can be infinite. However, the caveat from above applies: those lists better be at least somewhat stable if you want to be able to interact with them.
[1] https://developer.apple.com/documentation/appkit/nstableview...
The point about stability as an inherent need for good UIs is true. I'll keep it in mind when thinking about this problem.
Here's two examples I can quickly think about where web interfaces are more fluid than desktop ones: 1) new UIs on hover. 2) accordions. In https://unsplash.com/, when you hover over any image, three new buttons appear; all of them are interactive elements. And accordions are anything that expands on click to reveal more content - expanding a Twitter thread in the web UI is one example.
These kind of interfaces were very rare in the desktop world. Winamp was one of the rare UIs in popular memory that worked like that. I think they were rare because the tooling - static widget-based UIs made with form builders like Delphi and VB6 - made them very difficult.
But even if we fully code the UI using objects; like say in Qt, or even in Cocoa, I think the development experience and the robustness of the code is better expressed in a functional paradigm.
I think both of us are ultimately using the affordance of writing UIs to judge OO and FP as computational paradigms. I think UI is one of the most concrete but underlooked ways to discuss this topic and measure relative trade-offs.
I've been doing OO programming for about a decade, but recently something clicked about "computation" which I've tried explaining in the first section here: https://protoship.io/blog/how-functional-is-ruby/. It is something around "OO vs FP = Stateful programming vs Explicit/pure programming = Turing Machine vs Lambda Calculus"
I'm interested in this area because I've been trying to figure out a way to express UIs visually (like thru erstwhile Delphi or VB6 forms, or today's vector drawing tools like Sketch), but unlike all existing renditions, they have to be composable, reusable, and Turing complete. This is a little more tractable than it might seem if we use Lambda Calculus rather than Turing Machines to think of the problem, and so expect the interface to be pure and side-effect free.
I’m happy to answer specific questions.
Why do I, a framework user, need hooks?
What problem do they solve for me?
If you can't answer that without talking about what react broke first I don't think we we need whatever you're selling.
Added responses there too.
I feel like hooks are a solution to shit code that just needs a refactor.
This happens a lot in frameworks that try to please everyone all the time. You give people of all experience levels the same feature set. It's no wonder at least half your user base goes out back and shoots themselves in the foot.
If you want to fix this problem you need to remove flexibility. Not give them yet another method to hurt themselves.
I'd start by splitting component concerns. MVC might be a good candidate. React.fragment components tend to smell like fat models. Pure functions basically views and connect code/prop/state mapping looks a lot like controllers.
Fwiw this small UI component thing is originally what the MVC pattern was intended for. The big laravel style classes we have today are a misappropriation of the patterns name onto something that it shouldn't have.
They all basically say "framework needs it" or "we heard you like functions, so now we're getting rid of classes and making everything functions, but you still actually need classes and state and all that stuff so we're shoving state into globally accessible static functions that you have to call in the same order every time or things just won't work."
Like this whole thing is just absurd.
> They give you the ability to reuse stateful logic between components.
Stateful logic a code smell, we do not want this.
Redux actually gets this stuff correct - binding logic and effects to props and state should be done outside of the presentation layer.
I would have just fixed the redux API so people stop shooting themselves in the foot with it.
--- In any case, thanks for your comments, this has given me a lot to think about, I'm now wondering about how to replace useState with a prop named state. I'm also wondering if bi-directional prop mutation would solve all this cleanly - i.e. bind props instead of passing them, I think KnockoutJS did something like this.
Step 1: Get a simple "Hello world" running.
Step 2: Get something dynamic on screen.
Step 3: A simple if statement.
Step 4: A loop.
Step 5: User Input.
By the end of the guide, I know all there is to know to make a very simple interactive component.
FWIW, I think the current introductory material on the React site is not as effective as how things were in the early days. IMHO, a significant benefit of React in its original form was its simplicity. The whole API practically fit on a single screen. You could write a tutorial that showed the basics of rendering a component or two on a single screen. Today React itself has become more complicated, and the tooling around it even more so, and I'm not sure that extra complexity offers a good return.
Just as a demonstration of my point, please imagine for a moment that you are a developer who understands the basics of the modern JS world but is new to React. Go to the React site and find the instructions on how to just install React with npm or yarn, the way you probably would with any other JS library.
OK, so there's nothing readily visible. No, really. How to just install React like every other JS library in the world isn't even described on the introductory pages. Well, maybe you try running
{package manager} {install command} react
That used to do the obvious thing, but now it doesn't because even the essentials are divided among multiple packages with non-obvious names. So at this point, just a couple of minutes after you decided to give React a try, you're already confused about how it works in NPM and thinking basic documentation is missing, and you haven't even installed it or written a line of code yet.Maybe you find a link somewhere to the page about the "most popular and approachable toolchains". OK, that looks promising. You click the link and... you're confronted with create-react-app, Gatsby, Next.js and a bunch of other dubious, heavyweight tools, not that you know that because you've never heard of them. But there's still no sign of how to just install React and try it out like any other JS library.
So you go to the kitchen, make a coffee, come back and ask your mentor whether it's really necessary for you to use such a complicated and difficult tool, and whether you can just use Vue instead.
This comment is based on a true story. :-(
https://reactjs.org/docs/add-react-to-a-website.html
And it’s linked to from the other pages you mention with a disclaimer that a simple HTML page is still the best way to get started. Sure, you can ignore that, but what can we do.
But whether we like it or not, plenty of people want to kick off a single-page app with a whole toolchain rather than just “try React”. Earlier docs that you fondly remember didn’t help with that at all, leading to a lot of frustration.
Some people will be unhappy with either approach. That’s why the docs include instructions for both.
I understand that this is what the React team think. I am trying to explain that that page (and the other "getting started" level material on the current React site) is not necessarily working very well.
Maybe we're unusual, but among my professional network the overwhelming majority of React users do so with what now seems to be considered a custom tool chain, even if it's just "Bundler + Babel plugin for JSX". The first question everyone asks when they want to try out React, like any other new JS library or tool, is what they need to npm-install or yarn-install to get a minimal example going. And this information has now been hidden away several layers deep on the React site, as if it's an unusual use case.
Loading scripts from CDNs is fine for a very early experiment but quickly outgrown in production environments. There is create-react-app, but most people I know are sceptical about such tools and in any case it's debatable whether you want to start with scaffolding/framework tools if you're learning a new library for the first time and want to understand how it fits into everything else you're doing.
In short, the current site (and your reply here) seem to be predicated on a false dichotomy. Presumably you have access to better metrics than I do as a random individual and you know that most people really do fall into one of those two groups. All I can tell you is that almost no-one I know does, including those I have introduced to React myself in recent times.
Maybe it's just the curse of the modern JS world that everyone feels obligated to try to show how their individual tool or library works with 500 different other tools and libraries. Even so, there's probably a reason that almost every modern JS library's home page seems to have a screenshot with the words "npm install" in it above the fold.
Indeed!
> All of these motivations can be challenging to explain. So people tend to overfocus on “this”.
> I haven’t worked in many companies before, but I find my colleagues across the company to be very good UI engineers. Not sure where you got that impression.
It has its own section on the Introducing Hooks page :) https://reactjs.org/docs/hooks-intro.html#classes-confuse-bo... .
I can't recall if I've seen it brought up in other "official" channels, but it does certainly get talked about a lot in discussions such as this and I believe that's because of information sources such as the link. I will defer to you on the real situation, but I think hearing about classes and "this" being confusing, coming from React, is where people might wonder what's going on. Mentioning it at all may have caused a large distraction as people latch onto it as you say, and find the situation a bit incredulous.
In the mixins are considered harmful blog the point is made that sharing logic between components is a mistake and you should be using composition to achieve the desired outcome. Why do I need hooks? Is composition considered harmful now?
> * Colocate related logic instead of artificially splitting it into lifecycle methods.
Nope, all this did was make a mess. If splitting your logic into lifecycle methods was too disjoint there was way more going on in that component than their should have been. All useEffect and useState does is turn pure functions into mud that reads like a class but drops all the syntactic sugar that makes it readible.
> * Accurately model component as being in multiple states at the same time for concurrency. (Important for future React features.) Closures can do that because they capture specific props and state.
Besides this not making any fucking sense, why don't you call new and leave me out of it?
As a user, Why do I need hooks today?
> Finally there are some difficulties related to optimizing class code at compilation time. Such as inlining and fusing classes together. Functions make this simpler and they also minify better due to safer mangling.
Why do I need hooks?
Hooks are composable, unlike mixins. That's pretty much their whole point. Hooks are functions so you can pass values between them.
Consider that reading everything with a cynical mindset might be obscuring the design. I encourage you to play with it a little bit to get a feel for it.
>If splitting your logic into lifecycle methods was too disjoint there was way more going on in that component than their should have been.
I don't find this argument convincing. I'd love to see your take on abstractions for subscribing to data, form input, or animations that allow similar expressiveness to Hooks. https://medium.com/@drcmda/hooks-in-react-spring-a-tutorial-...
Dismissing them as unnecessary doesn't really point to any concrete solutions so it's hard to debate.
>Besides this not making any fucking sense, why don't you call new and leave me out of it?
Sorry, I don't know what you mean by that.
I tried to answer your questions the best I could. It seems clear that you don't find Hooks useful. That's cool.
I'd be happy to continue this discussion but I'd appreciate if you could tone down the aggression and snark a little bit. You seem to be very annoyed by our conversation, in which case I'm not sure why you talk to me at all. Answering comments like this isn't a part of my job, and I'd appreciate if you could at least talk respectfully even when you disagree. Thanks.
> Consider that reading everything with a cynical mindset might be obscuring the design.
I was concerned about this, I have pretty strong criticisms about redux. Well, actually, I love redux, I hate that flux dictated its design choices and blurred its abstractions which eventually resulted in the mess you now see in "userspace".
> I encourage you to play with it a little bit to get a feel for it.
I plan to, I'm simply still not convinced they're a solution that has a problem to solve.
> Hooks are composable, unlike mixins. That's pretty much their whole point. Hooks are functions so you can pass values between them.
Hooks are composable, yes, well sorta, at the top level, in a certain order, but if I want composable components I cannot use them.
By definition, calling a hook within a function gives it state. Once it has state, that function is no longer pure.
At that point, you may as well just use a class object and instance, at least then you can separate logic from state in a clear language defined way. This is preferable opposed to in amongst a bunch of useThis and useThat callback hell.
But I'm wasn't really arguing they're not composable, they API is a bit meh but its workable. I'm really just saying they don't have a reason to exist in the first place: Why do I need hooks? or why did/do I need mixins? What is the use case they solve when I have a correctly designed composable implementation of react components?
>> If splitting your logic into lifecycle methods was too disjoint there was way more going on in that component than their should have been.
> I don't find this argument convincing.
What is not convincing? Why does logic need to be colocated further than it is unless there is more than one thing happening in the component confusing things.
> I'd love to see your take on abstractions for subscribing to data, form input, or animations that allow similar expressiveness to Hooks. https://medium.com/@drcmda/hooks-in-react-spring-a-tutorial-....
subscribing to data - why would I want my presentation layer to be subscribed to data? The whole reason for binding data into the presentation layer via props is to avoid that proverbial shitshow.
form input - use browser builtins, if they don't work because react broke them then maybe react should fix them? or, you know, you just do what we all do right now - use a stateful react component class.
or animations - this smells like a jquery sales pitch. We don't need marquee, never did and never will. But see above, if it needs state, its a class.
I guess my confusion is stemming from the fact I don't see classes as a problem, or at least, I don't see pure functions as a sole solution. Pure functions solve a lot of problems by ensuring boundaries are correctly drawn and all state flows through props but that data needs to come from somewhere. Dropping state via hooks into things does the same thing redux does right now. Only hooks violate prop boundaries where as redux (correctly) respect them.
Personally, I would just fix redux if you have a problem with it.
> Sorry, I don't know what you mean by that.
"Accurately model component as being in multiple states at the same time for concurrency." - this is just words and needs a lot of context to unpack correctly.
(Important for future React features.) - As a user, I don't know or care about future React features.
Closures can do that because they capture specific props and state. - You know what else captures specific object state? Instances of objects. Call `new`, don't re-invent OO with pure functions.
All of which is besides the point ant still doesn't answer my question: What developer/user problem do hooks solve? Why should I use them as a developer? - opposed to refactoring into composable stateless components.
> I tried to answer your questions the best I could. It seems clear that you don't find Hooks useful. That's cool.
That's not quite correct I can see they solve the problem they set out to in an elegant, if kludgey, way. I'm just not convinced of their need (which still remains unclear and undefined)
Why do I need hooks? You keep falling back on framework or js reasons, these are not good enough reasons for a user to use, want, or even understand your new feature.
You've nailed it. Their solution to the issues with certain JS OO features was to re-implement Objects minus the features that were a problem, with new syntax. The code's worth a read for anyone who's read how the feature works and is still thinking "no, surely they didn't, it must work some other, magical way".