Hooks seem to be a drastic change in how we're going to write React components in the future. I'm quite satisfied with the current way of writing components which is to me is very explicit (with no magic). With Hooks React is taking a different direction from their original motto of explicit design patterns. From the looks of it, Hooks seems like a counter-intuitive design pattern but traditionally that's how most of the JS concepts were before they went mainstream.
I'm going to wait and see for some production success stories become giving it serious thought.
TBH, After reading the article I'm definitely putting effort to understand the thought process behind this change. Thank for writing up such a detailed & informative explanation on concepts in React.
Hooks make a lot more sense from a traditional FRP perspective. The code you write with hooks is basically identical to the code you'd write with early FRP systems. For instance, useState is called newWire in FranTk. The difference is that hooks have various limitations about where you can create them and how you can pass them around, which those FRP systems don't have. That's the result of React using plain old data as state, instead of having a signal abstraction as in FRP. In React the component function gets re-executed every time the state changes, whereas with FRP the component function gets executed once and builds up a dataflow graph that deals with the changes. That makes hooks very natural because they're just nodes in the dataflow graph.
Glad to read that as the top comment, because when they came out, I expressed strong doubts about this new features, and I mostly received mad comments in return. The alienated react fans stated that I didn't understand what modern code was, what a great idea those were and how from now on, everything will be better.
Now hooks are certainly a technically interesting pattern. I can see why it can be desirable by some. But I can't shake the feeling it has too of a big potential for misuse and could add a lot of complexity to a react, a tool that already has a big cognitive load with an ecosystem letting easily creep technical debt.
Besides, an important part of the JS community, up to now, has let me inconvinced about its ability to do the right thing, not to mention learning from other's past mistakes or even admitting when something is a problem at all.
> Glad to read that as the top comment, because when they came out, I expressed strong doubts about this new features, and I mostly received mad comments in return. The alienated react fans stated that I didn't understand what modern code was, what a great idea those were and how from now on, everything will be better.
Your post boils down to "Seems like it might be nice, but there might be bad sides, too" which seems fair, but the rest of your post is dressed up in a weird gloating dismissiveness and an exaggerated narrative about you, the epic heroic, fighting back the baying React Fans like in Doom's cover art.
I wouldn't celebrate your skepticism just yet, especially not just because you found someone else on HN to commiserate with.
The behavior that you see from a system is the behavior that that system encourages. I guess the proof will be in the pudding as to what hooks actually encourage.
I find a healthy dose of 'gloating dismissive' skepticism is usually a good thing. Because it stands in stark contrast 'gloating dismissive' dismissals of criticisms as 'nonsense' that usually come in the form "nah you just don't get it".
UI paradigms in particular warrant a good deal of skepticism in general. Every time it's "this is way!!!" and there are a whole slew of issues people regret wading into eventually down the line. Then new stuff comes out to fix those issues and "THIS is the way!!!" with the assumption that the new way doesn't have it's own problems (or at least the optimism is just ignoring them as they aren't salient enough yet to impact thinking). This just keeps playing out over and over. No reason its different this time.
So, I think it's absolutely fair to say "I wonder what nastiness come along with hooks that we are accepting as a trade-off for the potential benefits of Hooks?". At the same you can't compute the actual result as an intellectual exercise, so a healthy degree of optimism is warranted too in which we also ought to say "I'm excited to see if this really is the way and maybe we wont arrive at front-end utopia just yet, but hopefully we will get one step closer through the learnings".
> could add a lot of complexity to a react, a tool that already has a big cognitive load
I don't understand how hooks add complexity or cognitive load. Simple cases stay simple (even more so, and it's harder to mess up with useEffect than with lifecycle methods, for example), and complex cases are less so.
From the point of view of someone with years of experience writing large applications with React, hooks are a very pragmatic move that solves real problems precisely by simplifying what was already possible. The more complex the scenario, the more obvious the gain is. I venture to say the same thing about the upcoming suspense and related features.
I don't think React itself has a big cognitive load anyway. You might be attributing to it the difficulty some aspects of functional programming might present to some, or of some libraries you might have been using with React. I found this to be the case often. Forgive me if I'm guessing incorrectly.
I don't know a big react project that doesn't bring in a massive ecosystem with it. Standard is at least a complex webpack setup with a store and a routing lib.
But more than that, react based code has a lot of indirections, requires a lot of pieces of the puzzle to figure out what's going on, and projects have so many different styles and layout you never feel at home when you switch.
The best exemple is jsx. Not only you need a transpiler, not only do you mix in the same place representation and behavior, but the code looks like either spagetthi inlines, or, if you are lucky, a list of many references you suddenly gotta check up somewhere else.
The thing is, with classes, you have a little guidance on where goes what, and people still manage to screw that up. With hooks it's free for all, with caveats, so reading somebody else's code is going to get extra fun.
I have the exact opposite perception. Previously, I used to convert a function/stateless component, just because I need one transient state and it felt very verbose to switch to class components, while all it needed was one state and corresponding setState. With Hooks, all of them just become more transparent (you explicitly have to hook all the states, not just use one state and add later add more states to track). Though I admit I felt uncomfortable initially, it just feels right once you start working with them. I really like hooks!!!
My litmus test for technology is whether it results in a) fewer lines of code b) simpler code and c) does it make me more productive. My experience with using hooks is that I rip out lots of cruft and it is easier for me to get my head around how to write things so I am more productive. The cost is learning a new paradigm, but the benefit for me was very high.
I strongly recommend you temper your criterion `a` by how much the abstractions help or impede your understanding of the code later on, especially when trying to diagnose a bug.
Hooks fix some of the composition headaches you get from render props, which is the current standard for composition (the heritage being HOCs -> render props -> hooks). They're basically mixins with weird syntax.
The syntax isn't even that weird? It's just function calls.
The only "weird" bit is using array destructuring for multi-return and that's been in ES/JS for some time now, and definitely shouldn't look that weird to anyone that has worked in Python, as one example (and C# now supports destructuring even).
Also, hidden state/context is also not that weird? Do you need to know the exact location of the memory/stream that `console.log()` writes to in order to log the console? The physical details of how `navigator.compass.getHeading()` gets its information to use a compass heading? Both of those trampoline off into native code and the details of what the actual "explicit" locations for them is both irrelevant and highly variable depending on browser and system.
Unless you are looking at the namespace "objects" such as `console` or `navigator.compass` as "explicit locations", but you can add namespaces to your imports if that helps you feel like things are more "grounded". Import it and use it as `React.useState()` instead, for instance.
The hooks calls are unusual compared to normal Javascript code. If you read the other comments on this thread you'll see that I'm not the only one saying that. It comes down to the fact that it's a call, inside a render function, that has different behaviour on each call to said parent function. It's very magical - and the React team admit that, so I'm not sure what exactly you are arguing against.
It's not like I'm new to Javascript either - I've been coding in JS for over 10 years. I understand how it works, but it's still weird-looking code. You can hack up the language to make stuff like the new hooks library, even without the unique quirks of React's internals. But libraries that intentionally do that to generate magical effects are generally considered "weird" too.
I appreciate something about it feels weird to a number of people, and it feels that way to me at times, too. I'm just pointing out:
In JS call order always matters (it's an imperative language full of side effects), and many calls have side effects that very much differ based on the order you call them.
Even if the gut reaction to hooks is that they "feel" magical or quirky, it's not that different from how a lot of black box function calls already work in the language, it's just maybe more obvious with hooks because they are more explicit in the rules on when you should call them.
Which isn't to denigrate feeling weird about hooks. Again, even I still feel weird about them sometimes. Just that it is less unusual than that initial gut reaction seems to think it is.
Edit: this is one reason I don’t do the social media thing. I read that in a totally different frame of mind than you wrote it in, probably. I am not one to get all preachy. I personally get caught up in analysis paralysis sometimes because everyone has convincing arguments. It’s because there are many right answers. There’s probably some deeper psychology there... dunno but it’s on me.
No offense, but it would sometimes be good to remember that quote about sufficiently advanced technology being indistinguishable from magic when taking such an authoritative tone.
There are probably some other equally talented developers who do ‘get it’ who might be a little unsure of themselves and continue to hold back and feel like an imposter.
Anyway, that’s not really a call to change or anything. You do you.
But I did want to remind everyone else, especially those unsure of themselves, that those are, like, their opinion... you also do you.
Are hooks being accepted as a good design by the community?
It seems to me that the lack of a parameter explicitly indicating the component and the reliance on hook ordering to match them across calls of the component function make them a bad design, but I might very well wrong and would be happy to be convinced otherwise.
Hope this helps, happy to answer questions. We’ve been using Hooks for several months at FB and haven’t seen confusion caused by the call order reliance.
(Note Hooks don’t rely on specific call order but just on it being static between renders. Which is pretty easy to understand and reasonably enforce in practice.)
When I first encountered hooks about a month ago, I was absolutely confused about how the `a` in `const [a,b] = useState(...)` was just a plain JS object and not some magic proxy. It took me a good hour of researching before I understood that it was because React stores state that remembers the last time it called your component. I think a 20 second well-thought-out gif would clear this up for everyone who doesn't have an hour to devote to understanding this, and I strongly recommend considering it.
One thing that looks 'magical' is how does the setWhatever function lets React know that state has changed and has to re-render? Is there any info/writeup on this anywhere?
> React knows which component is rendering at any point in time — so it knows which component useState() call corresponds to.
Personally, I think that may be the piece that makes it feel a bit magical. With `this.setState()`, usage of `this` makes me feel like I know how the component and the state are linked.
With hooks, however, there's no obvious link to the component in the code. I'm grabbing `useState` off of the shared react module, `useState` is not passed into the component, and I don't have to reference the component itself at any point while using hooks. The new sets of rules you have to follow to make things line up correctly play a part, as well.
Of course that may be how `this.setState()` does it anyways - you know better than I do, obviously. Maybe the usage of `this.setState()` made me feel confident in something I didn't actually understand under the hood. But at least for me, that's why `useState()` feels a bit magical at first glance compared to `this.setState()`. Not _too_ magical, and not enough to scare me away from using hooks, but still a bit.
Conceptually Hooks are modeled as "algebraic effects" feature from languages like Eff and Koka. Those are essentially like resumable exceptions.
With that conceptual model, `useState` is like a `throw` that goes back into React "up the stack", and then goes back into your code.
Of course that's not how it works for perf and other reasons (there's no resumable exceptions in JS). But this may help the conceptual model around how we know which component it is.
The component renders any time the setWhatever function is called, similar to this.setState() in class components. The presumption is anything that you're storing in state is depended on by the component. If it's not, it doesn't make sense to have it in state anyway.
It's basically the magic vs explicit discussion all over again. Like usually in this discussion, the magic approach is really appealing until it doesn't work, and then the pro-explicit people will go all "told you so" on you.
I personally really prefer explicit, having cut my fingers on magic one time too often. Instead, I'll gladly create classes if the thing I'm making has its own state (of any kind).
In fact I pretty much disagree with the current trend of wanting to shoehorn everything into this idea of declarative and/or functional programming. Especially in a language like JS, functional programming and some cherry-picked ideas from OO mesh really well together. For example, if you allow me to drift a little, did you know that you can add methods to the prototype of an Immutable.Record? You can even use class syntax! More to the point, if there's one place where OO ideas shine, it's UI components. A lot of OO ideas were particularly designed and developed for UIs.
Just like "let" and "const" let me communicate to the reader whether a variable is going to change, I like how in React-land "class" and "function" let me communicate to the reader whether a component has mutable state. Hooks feels like a hack to be able to change the value of a "const" without turning it into a "let". Get over yourself, make it a "let" already.
So for me, Hooks is an attempt to throw the baby out with the bath water. I don't experience the problem it's trying to solve. I like classes when they're appropriate.
I get the argument that custom hooks allow for easier reuse than higher order components, but I think the difference is marginal; you have to wrap your mind around the exact same complexity. Plus I think higher order components themselves are overused, but that's another story.
But! The React people strike me as a rather reasonable bunch. I strongly doubt they're going to move React into a direction where you're forced to make your state (slightly more) implicit. There's too varied a community around React now. I think React with classes and React with hooks can perfectly coexist. Also if my favorite open source React tool adopts hooks and forces me to do the same here and there, then sure I might be grumpy for a few minutes but in the end, well, I'll survive.
> It's basically the magic vs explicit discussion all over again. Like usually in this discussion, the magic approach is really appealing until it doesn't work, and then the pro-explicit people will go all "told you so" on you.
Well... Have any "pro-explicit people" gone all "told you so" about all the magic that's going on with setState?
I don't think so. I don't think it's a binary magic vs explicit choice. I usually lean towards explicit, but as setState demonstrates, it's possible to find some kind of balance where the benefits of the magic outweigh the downsides, or at least are not that bad of a choice.
There's nothing wrong with `setState`, in my opinion. However, it does do magic. Although it might feel like it immediately sets the state to be what you provide it as argument, it actually schedules a state update to be performed later when React feels like it. That's why it's best practice to provide an updated function rather than a plain object: if the new state depends on the previous one, and you read the previous state before calling `setState`, then that can lead to problematic behaviour.
(And of course, there's the magic of the returned object not being set as the new state, but rather being merged into the previous one.)
I think the more relevant analogy between hooks and setState is that setState uses essentially the exact same technique as hooks to keep track of which component is calling it, namely, React keeps track of which component it’s rendering, and setState mutates some “global” state. A lot of people seem to think that setState stores state in the instance of the React component class, but that’s not the case (and that wouldn’t work for a lot of React features and optimizations).
Is this true? Maybe I'm reading it wrong but this.setState in a React.Component just transparently calls out to `this.updater`[1] where `this.updater` is injected by the particular platform library (eg react-dom). At least in react-dom/server's case, a unique `updater` object exists per-component[2], so it's effectively a private instance field; and those state changes apply to a similarly per-component `inst.state`[3]
You can also prove this by calling setState with the wrong `this`: `this.setState.call({}, {x:1})` blows up. So the `this` is required, unlike how `useState` works.
Which is also something beginner React users often discover the hard way when they start with class instance variables, wonder why things don't work as they expect, and then have to learn to use setState.
At least from the principle of least surprise, Hooks don't have that particular learning hump of trying to use a built-in language feature (class instance variables) and finding out the hard way that they don't work as expected.
> setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state.
(Emphasis mine.)
> I'm guessing you mean for a global store with shared state? Local components aren't singletons.
No, local state, the one you set using `setState`. The offical docs don't actually recommend always using an updater function, but it's the primary method they explain, and my inclination is to better be safe than sorry:
> If the next state depends on the current state, we recommend using the updater function form, instead
Apparently nothing, but from how I read it a lot of magic is going on underneath the covers (which I cannot really imagine, if react is as simple as it claims).
I'm using them on my current app, and have no intention of going back to classes.
> lack of a parameter explicitly indicating the component
That's sort of the whole point. That you can write general purpose side effect functions that don't need to care about which component they're being used in. It's super easy to have a toolkit small unit testable functions that do the pretty much all the work in the application. Far easier to work with than inheritance, mixins or traits. Easier than composition, even, because this is just calling functions. If you're familiar with using Underscore or lodash, this model will feel very intuitive.
> reliance on hook ordering
This is a red herring, because we're only talking about execution ordering when the code runs. It doesn't actually matter what order I write any code in, only that when the code runs the order doesn't change between two render frames. This is as simple as don't have conditionals outside the hooks, have them inside. If you think of hooks as accessing the state register by the index of their first access, it works well as a rule of thumb.
The real problem is the impedance mismatch that the line above causes - you need to remember that hooks access the state register by order of their first appearance, not by identity. So if hook no. 3 doesn't execute on the second render for some reason, hook no. 4 will see hook no. 3's data. This goes very contrary to JS or any other programming language / paradigm I know.
It also has repercussions (https://overreacted.io/making-setinterval-declarative-with-r...) that are unintuitive, because the identity of the functions you pass into the hooks is lost as well, so you need to put them into the call-positional state register via a ref.
To be honest, I haven't hit that edge case yet, and it's easily handled once you understand the system for what it is. It is very un-intuitive to program this way, but it's not a problem most of the time.
Just remember that the identity of the state of any hook is represented only by its sequence number of execution during the first render, and you can figure out the remaining gotchas from that.
It shouldn't feel that unintuitive, it's not actually that uncommon in JS and/or any other programming language that the order of calls matter. It's basically a fundamental quirk of all (side effect full) imperative code. It's the languages where call order doesn't matter than are much more rare, and are more generally considered unintuitive (for instance, Haskell pure functions).
The cannot be called in conditionals and/or loops need is certainly more rare, but it's also not necessarily an exotic thing: so much of debugging and performance work in the average imperative language is often finding things called conditionally or in loops that shouldn't be and moving them up/out. Some things like setInterval or certain types of awaiting large expensive computations you almost wish you had lint errors in place to forbid them in loops (or even sometimes to forbid them from conditionals in cases where they don't happen cause subtle bugs).
I don't think this is contrary to JS at all. It's different and may take some time getting used to, but "call order matters" isn't unusual for JS (especially in the world of DOM manipulation).
class ToggleButton extends React.Component {
flag = useState(this, true)
count = useState(this, 0)
other = useEffect(this, () => {
...
})
render() {
return <button onClick={() => this.flag.set(!this.flag.current)>{this.flag.current}</button>
}
}
Then it's very clear that we have two separate sections: initialization and rendering. There's no longer a hidden state stored somewhere else, but you know that if you have the same `this` then you have the same state.
Personally, I don't find it any more concerning that many software engineers with extensive professional web development experience had such a difficult time understanding React when it came out. (It was universally ridiculed and dismissed for about a year after it came out.)
It's a different mental model. It doesn't "click" immediately for everyone but I've seen it "click" enough times for both beginners and experienced developers that I'm not worried about it.
I don't really remember there being much of a misunderstanding of React itself when it was first launched. There was definitely ridicule ("markup and logic in the same file?!"), but the general idea behind the core of it is pretty straightforward. I could be misremembering, it has been several years after all.
And I'm optimistic that hooks will be great and they won't be difficult to teach to React newcomers and more junior team members. But it's not obvious to me yet that it's the case and I'll be careful about how I use the feature going forward
Thanks for all your contributions to the community, though. Not trying to be overly critical of all the hard work — just trying to fully understand use cases, maintainability implications, etc.
I would question the premise. I consider myself fairly plugged into the professional React community on Twitter, and I have several years of React experience myself, and my impression has not been that experienced React programmers have a difficult time understanding hooks.
Same. Most of the devs I know personally were immediately convinced and loved the API. I assume the usual feedback bias is at play here.
Folks who are into hooks probably talked to friends/coworkers excitedly about them, but have a lot less reason to broadcast their feelings about it than people who had complaints. I don't think any of the people I know who were into them did anything more than than thumbsup the RFC or like/retweet some tweets--if they even did anything public at all--even though we all followed the discussions. Personally I didn't want to add to the noise with a comment which would basically be "Yeah this looks fantastic, and all these alternative APIs being suggested seem clearly worse."
People who don't like hooks spent a lot of time writing about their issues with them and what they'd like to hear instead. I wish I could get that type of feedback on everything I wrote, I just wouldn't want to deal with that immense volume.
This is such an excellent point. I made a prototype of a class based alternative to hooks, and while I liked some aspects of the API more, it definitely did not take this use case into account!
My impression is the community is mostly accepting, but some are taking a wait and see attitude until they can see it in production.
I don't think there's a lot of concern about hook ordering; it's hard to see that being a serious issue in practice. And it has some significant advantages over existing alternatives.
Maybe it won't be an issue. However, it does go against regular advice of being explicit over magical. Depending on call order is something that immediately pops out as fishy.
As always, programming is about trade-offs and the React team is claiming this trade-off is worth it.
That's not why you have to do it, it's because the state can be updated asynchronously. It's only applicable when you try to update the state based on previous state or props values.
tl;dr: The primary design goal of hooks is to support the creation of custom hooks, which can eliminate the need for higher-order components in many cases. An ideal alternative implementation would support custom hooks, without relying on call ordering, and without requiring a linter to guarantee safety. Unfortunately, there doesn't appear to be an approach that satisfies all of these requirements. Depending on call order is apparently the least-bad approach to hooks.
Hooks future depends on its objective: a replacement or an alternative?
I guess even the React team itself doesn't have an answer for this, that is why they are rolling out Hooks relatively cautiously, not forcing it down to the community like what angular does with its 1.x -> 2.0 push, which I consider as a complete disaster that eventually costed it the victory of last framework revolution.
My bet will be on the later. Hooks will become a preference, and there will be a mix of hooks/classes in real world application, since rewriting using Hooks only isn't what most people see will bring immediate benefits. The React community at large from my observation doesn't have a huge issue going forward with the current API, despite being grumpy from time to time.
Everyone is calling this "magic" yet under the hood it's the same "magic" behind a react component class setState function. It's literally the same thing, but lets you pass these functions to descendents. It essentially decouples that "feature" from being tied to the class component. That's just excellent.
I've read a lot about hooks, the reasoning all makes sense but I'm still not fully getting it at an intuitive level. Like I get that it means you can write functional versions of class based components, an example of a complex class component that has been converted to a function with hooks would be good. The counter example really leaves a lot to the imagination.
The examples in https://usehooks.com/ aren't convincing me for some reason, but maybe that's just my lack of familiarity with the syntax so it feels more magic. Lifecycle methods like componentDidUpdate are super easy to reason about at first.
A major point of Hooks is that they’re composable — unlike lifecycle methods.
You can separate different reusable pieces of logic into Hooks, and then combine them or pass values between them. You can even call the same Hook more than once.
I’ve wrote about new possibilities they unlock here:
But why does Hooks need to be implemented on top of functions and not classes? The way I see it is that Hooks today implements two distinct things: (1) a composable way to handle lifecycle and (2) a custom way to store state. Why can't we have the composable hooks available on React.Component like this?
class Foo extends React.Component {
constructor(props) {
super(props)
this.useEffect(…);
this.useState(…);
// or maybe even a top-level API:
useState(this, …);
}
}
https://codesandbox.io/s/5vvm68k6qp. The custom effects would take functions instead of values and then `useEffect` will be executed by the component. There's certainly some issues in this implementation with regard to how to handle nested state changes, but I think that can be worked out.
I like judofyr's solution to this as well, but I think hooks that change the internal state of component are a bad idea, and breaks encapsulation in my mind.
I've used the hooks myself and I like the composability, but I can also understand the vitriol from the community. And so far my biggest complaint is that I can't use them in classes as well. I think if you treat them as a more core/composable type of object then you can use them in the same paradigm as Component classes.
My example here changes the names of the typical lifecycle events for clarity but you could use the component lifecycle names instead. Point is it should match the component lifecycle and allow the user to hook into each one separately but wrap everything up into a meaningful collection.
A hook must be declaratively defined as a property in another class (I use the @annotation syntax here but I realize it's not standard yet), and that allows react to keep a consistent ordering on how/when hooks are called during lifecycle events. It also allows the hook to register itself for the lifecycle of the owner.
<code>
class UseWindowWidth extends Hook {
// normal style of using state
state = {
width: this.props.value
}
// or maybe use state hook for new style
//@hook(UseState, this.props.value)
//width;
handleResize = (evt) => {
this.width.set(window.innerWidth);
}
hookDidMount() {
window.addEventListener('resize', this.handleResize);
}
hookWillUnmount() {
window.removeEventListener('resize', this.handleResize)
}
getWidth() {
return this.state.width;
}
// other public methods here would allow owner to do things
// ? although this doesn't fit well with top-down props style
}
class MyComponent extends Component {
// @hook registers the hook into lifecycle events and
// passes props to UseWindowWidth hook. Also, any changes
// to hook state should cause a forceUpdate of the component
@hook(UseWindowWidth, { value: window.innerWidth })
windowWidth;
render() {
let width = this.windowWidth.getWidth();
return (
<p>Window width is {width}</p>
);
}
}
</code>
The 'props' concept might not make sense with the Hook object as I have it here, cause I can't see a nice way to declaratively update the props instead of just calling setters, but that might be ok for how these would be used.
I'm not in love with this yet, and there's some other things that would have to be ironed out (like coordination between hooks), but I think it opens some ways to allow hook use in class components as well.
Appreciate the response. I think at the moment the onus is on me to experiment with the hooks api more and hold off any judgement. Conceptually I'm fully with you, I just need some hands on experience. Plus anything that stops me making token HOC's for Redux just to interact with my global state can only be a good thing.
Grouping these parts this way means they can be trivially extracted as a Custom Hook[1] (analogous to a 'mixin' or 'trait' in OOP).
By extracting this concern into a Custom Hook it can easily be reused by different components, as well as composed by other Custom Hooks. This was previously possible using Higher Order Components, Render Props and the (really old) React Mixins concept, but Hooks addresses problems with each of these previous approaches.
It's a little harder to wrap your head around for sure.
But the benefit is tighter encapsulation of functionalities. No longer do we have to spread a feature's logic across multiple lifecycle methods that may share that space with logic from other features.
I don't get it. I thought the main appeal of functions were that they were stateless so you had immutability. We already have classes if we want state, so why is this an improvement? Functions have slightly less overhead maybe? But then why didn't the React team just work on making classes have less overhead? It seems sort of "extra".
You should think about it in is this way - class components do not actually control its state. Using classes is just a convention supported by React that allows components to express their intention about what state they should have and how it should be updated, so it is just a form of interface. And hooks is a different way to interact with same underlying subsystem of the React, but they allow you to abstract, reuse and compose the logical parts of the interaction with the state.
I've been working with hooks for quite a while now; its main benefit is composability - before hooks up you rely on Higher order components (HOCs, HOFs but in component rendering) to provide composability of component behaviour - this is messy, very messy, and not performant.
By using hooks the logic tidies up massively (so working on it becomes a lot quicker) and several hard to diagnose performance bottlenecks disappear.
They can always be factored out into a function, after all, both HOCs and hooks are functions. One big (or at least obvious) benefit of hooks over HOCs is the fact that they can be composed without the possibility of prop name conflicts.
Well they can, except that function needs state as a parameter or calls from lifecycle, which means changing many places inside the component to have that state as well as call that component.
A HOC previously served as a minimally invasive way to compose these behaviours (compose the HOC + use its param in render).
If you are writing a moderately complex animation, you can quickly end up needing state, willMount, and willUnmount, plus the render change plus the logic, thats five places in a class. If this animation applies to many components you abstract to a HOC and simplify dev overhead at a performance cost.
Using a hook lets you abstract that all into one function as you suggest.
Most of the HOCs I wrote had to do with just local state + store state + logic, so not as extreme (editable, updatable, draggable, deletable etc.); but when you have many, the penalty adds up.
I'd encourage you to read through the Hooks docs [0], which explain the motivations, and Dan Abramov's posts on some of the internals [1] and what problems they're meant to solve [2].
For the vast majority of web apps, you’re going to need state that changes over time. Making individual components immutable is a nice architecture choice for several reasons, and hooks doesn’t really change that. Hooks just provide a way to plug state (which can change over time) into your components, which is something you already had to do. Where you were previously using class components, HOCs, or render props, you can now optionally use hooks, which have some well-documented advantages.
Not specific to React, but with CommonJS modules you can use module scope instead of global scope to get private methods and variables, which the function can access via the closure.
var foo = 1;
var bar = x => x++;
module.exports = function baz() { return bar(foo) }
I find this much more simple then classes. I even consider it an anti-pattern to make a class for something this simple.
That gets you a single instance, but the whole point of React components is that you can use them lots of time and each will do its own instance of the thing.
The next dev that comes along and naively imports your module into another part of the app will waste their time trying to figure out why foo keeps getting overwritten by the second instance.
To add to the other answers, the type-ability of hooks is so much nicer. useContext means I'm going to be using context a lot more in TypeScript code now that I don't have to add a bunch of type definitions to every component I want to use it in.
Based on the consistent supply of comments sharing hesitation/confusion whenever hooks are talked about, I'm curious. Is this a normal reaction to a new thing that ends up being a very good idea? Are there past examples of this? I can't quite tell if it's a sign that something's off or if this is just normal.
Well, when React first came out no one was convinced by it. It took more than 2 years, I guess, before everybody suddenly got convinced and started claiming it was the best thing and so on.
I was not convinced either, Code and UI together!. If you ask me now there is nothing better then reactjs out there. I would not hesitate to change if there was something better.
Now we can finally have completely clean data loaders:
Create a data loader hook that loads your data in a one-shot effect (you pass it the identities array), and which returns either a valid view (an error or loading view) and no data, or no view and valid data of type T. Then you can just do:
Never a boring day being a frontend developer. Looking forward to add hooks to my React project. The next frontier would probably be functional strongly typed languages, like Reason or some variation on Elm?
Well, he said "the next frontier". Probably implies that Elm didn't catch on, and means "what will the next major framework/paradigm/fad will be post-React".
I honestly don't think that there will be another framework that'll overtake react anytime soon. It's not about there being a better framework, just that we finally have something that's "good enough".
I would say the same for Elm architecture and type system that guarantees no runtime exceptions. There is nothing similar in frontend languages and frameworks.
Something that I really like about React is that it is easy to reason about the state of each component, with functions there was no state, with classes, you can see everything that touches the state there in your class.
I am not sure how having various functions (hooks) that trigger state changes and so re-rendering is going to pan-out in practice.
Here comes setInterval and counter packages, no I don't believe I can simply avoid using them, everyone depended on leftpad, indirectly.
How is this different to using a React component installed from npm? You can look inside them if you want to, but don't have to. That is the goal of abstraction.
If you want to have no abstraction and show all state in your component, just don't extract any into Custom Hooks. Then it's really not very different to a class component.
Looking forward to updating my current project later today. The mess of HOCs, local state, context and props flying around have kept me busy looking for alternative frameworks in the past few years; without those it might actually start being consistently enjoyable.
This is exciting, and at the same time I wish this came out before writing thousands of lines of code on my React app...
I can see the possibilities this brings, and they're much better than the mess of props, local state, redux, and HoCs that we have. But the refactoring needed is just insane.
Has anyone gone through something like this and has any tips?
The primary tip is: don't refactor. It's unlikely to solve any problems if you already have working code in which you've already dealt with all the hassles of HoCs and such. You can just start using it in new code to avoid having to deal with it for that.
I follow this sometimes but having a wide range of patterns in the same project feels so dirty in a way... Although it makes sense, refactor only when you need to.
I understand. I feel like the consideration to make is: will the benefits of hooks outweigh the benefits of mixing different patterns? If your estimate is that it won't, I'd stick to the current patterns for a while, rather than rewriting them now - because I'm quite sure the benefits of hooks aren't going to be worth the rewrite.
I feel like most production React I've seen already has a mixture of components written as classes versus ones written as functions versus functions and classes written to be HOCs. Adding Hooks in most codebases won't make most of them feel anymore "mixed" than they already were.
Why refactoring? It might be marginally better, but it doesnt mean what has been written in the past is wrong. Plus unless you have very robust test coverage, refractoring at this scale is going to introduce more bugs than the marginal benefits it will bring.
Do it piece by piece. There's no need to do it all at once, so start incorporating it where it makes sense when opportunity shows itself. By doing a massive rewrite you're just inviting badly structured code.
One thing I can’t figure out in hooks vs recompose is how to use them and avoid props drilling or even just basic wiring. One of the most glorious things about recompose is that the props are drilled/wired for you automatically. This turns out to be huge for me. I had so much tedious props drilling code that just went away with recompose. Anyone have any insight?
Fun approach! But I don’t think that’s it? Just not the same kind of zero-effort awesomeness right? Also uses the context API for something it’s not intended for.
I'm not sure what you mean — the context API is specifically for moving data around the component tree without prop drilling. What are you talking about with regard to recompose?
I guess I just mean wiring. Recompose eliminates the need to do any wiring at all. You compose up your component, and then you have access to all those props without having wired them! The last thing I want to do is get the context API involved.
Slightly off-topic, but has any of those who dislike hooks for the added magic seen Svelte.js version 3? It is ridden with magic. Top-level variables in the <script> block are "observable" in the Vue sense of the word and accessible in the <template> block; so whenever they change, the relevant parts of the template get updated. The creator of Svelte says that it's very intuitive, and that developer experience is great. I wonder what your take on that will be.
To be fair Svelte does have the word "magical" in its motto.
I personally don't see it as anymore magical than MobX - it's just taking it a step further by taking advantage of the fact that bindings are created at compile time.
This is consistent with how things are generally done in this framework.
Not a fan of that non-JS svelte magic or the direction these frameworks are going. Fewer lines of code, true, but at the expense of understandability. I just want to get my work done, not learn yet another flavor of the day with non-intuitive implicit behaviors.
I am generally with you, but the purpose of these frameworks _is_, first and foremost, to get work done (Svelte's creator Rich Harris says that it makes it possible to write UI components very fast). I love it when the code is explicit and when the framework does not introduce any weird shenanigans (Backbone, where are you? I am missing you), but this explicitness comes at a cost of having to write boilerplate.
> it makes it possible to write UI components very fast
...until you happen to code something that doesn't follow the magical convention and everything breaks for unknown reasons. Then it becomes difficult - or impossible - to debug.
The crowd is too fatigued to get excited anymore, there is a handful of outspoken people who will cheer any change for the sake of change or saving up a couple of key strokes at the cost of long term API size and maintenance burden. but it is getting tiresome.
Nah, HN is jaded as usual but every React dev I've talked to outside HN has been looking forward to this day with excitement ever since hooks landed in alpha.
I've yet to see HN get truly excited about anything JS-related, particularly React. Personally I'm excited but I wouldn't bother elaborating my excitement here because I know I'll just attract the usual crowd making unfound assumptions about my experience or complaining about hooks not following best practices (like, I don't know, JSX?).
Yes, it gets a bit tedious seeing 90% of comments on HN being from people who clearly haven't tried the thing, or even given it any thought or consideration beyond an initial "this is not familiar to me so therefore bad!" kneejerk reaction. It's not a great look for a developer and I don't know why they seem so proud of their close-minded attitude.
Yes, it gets a bit tedious seeing 90% of comments from React fanboys being from people who clearly just repeat each others arguments, or even give no argument at all beyond "I'm assuming you are stupid because people who are not clearly all love this feature". It's not a great look for a developer and I don't know why they seem so proud of their close-minded attitude.
This is basically the NPC meme but for technologies instead of politics.
I've been building websites since the 1990s and web applications since the mid-2000s. I've used a wide range of web technologies and despite being "self-taught" went out of my way to broaden my horizon beyond the imminently useful.
My initial reaction to JSX was dismissive ridicule: "XML in JS? Yeah, because that worked out so well when we did that in ActionScript. And building your own component tree as a template language was already a bad idea when I rolled my own implementation in PHP fifteen years ago".
My initial reaction to hooks was confusion: "The sequence is important? Why wouldn't you just name things instead? Why does everything start with "use"? What the heck is even going on?"
Both times I looked into it and realised I was wrong and my intuition was just rejection of the unfamiliar and a profound misunderstanding of how the technology I was dismissing actually works.
I'm not a "React fanboy". I can't say what framework I'll be using five or ten years from now. It doesn't look like there's anything around that I would choose to replace it (though I have to admit Vue is a contender if only because it seems more beginner-friendly) but I've gone through enough technologies all over the stack not to make the foolish assumption that the things I use today will be the things I use in the future.
I was confused by hooks, so I paid close attention to the demos and explanations. I learned how they work and why they have the limitations they explicitly tell you to be aware of. That's when I got truly excited. Not because I was dazzled but because I saw the potential and understood how they compared to what I am already using.
Stoic sarcasm went out of style in the 90s. Maybe you should give empathy a try. Maybe, just maybe, some of the people who are truly enthusiastic about hooks aren't simply naive, maybe some are enthusiastic because they do understand how hooks work and what implications they have.
> Maybe, just maybe, some of the people who are truly enthusiastic about hooks aren't simply naive, maybe some are enthusiastic because they do understand how hooks work and what implications they have.
In the exact same way that some of the people who are not enthusiastic aren't people who haven't looked at Hooks and don't understand them. Maybe they aren't enthusiastic even though they do understand them.
That is exactly the point. Not your experience since the 1990s or my sarcasm, but not assuming that if someone does not agree with your view must be because they don't understand.
Here's the thing though: people who use React and comment on React news on HN are a tiny fraction of the overall React community and due to the nature of HN a lot of people comment on topics they don't have significant interest in.
Negativity is the cultural norm on HN so much that many people look at HN ("the orange website") the way HN looks at Reddit.
I'm not talking about constructive criticism, heck even non-constructive criticism would be a welcome addition if at least it attacked something more foundational than e.g. "relying on call order is a footgun" (which btw is true but ignores the many footguns involved in the APIs hooks are replacing).
You haven't given a single argument why "hooks are bad if you understand them". That makes you indistinguishable from the usual drive-by negativity. If you want to appear like you have something to say, maybe you should actually say that instead of just insisting your opinion is based on something substantial.
For the record here are the top level responses to the original comment I responded to:
* omeid2 says hooks are change for the sake of change and they only help saving a few keystrokes
* geezerjay says hooks bring nothing new (then pivots to "no new features" when pushed on it)
And then there's my comment where I say HN is jaded.
The first response by omeid2 is demonstrably false: hooks allow collocating all code related to aspects of your components that previously resided in lifecycle methods. They also get rid of the leaky abstraction of `this.state` and `this.setState`, make it easier (read: less error-prone) to respond to prop changes and eliminate the indirection required to consume contexts.
The second response by geezerjay is true in a trivial way and false when taken at face value but further downthread he doesn't elaborate and instead just insists he's not being understood.
Meanwhile your entire contribution so far can be summarised as "no you" at worst or "some people don't like hooks even though they understand them" without going into any tangible specifics at best.
I said nothing about loving, or even liking, hooks or React itself. That's not the point. It's weighing in with a completely useless opinion based on a second's thought, over and over again.
There are trade offs and it's interesting to discuss those and to criticise them. But a kneejerk reaction can't go that far.
You've missed the point entirely. Hooks offer nothing new because their functionality was already implemented in React class components.
They literally add no functionality to React. The docs actually state quite clearly that developers are discouraged from replacing class components with function components.
"No new functionality" and "nothing new" are two different things. Improved developer experience, decreasing the surface area of bugs, etc - all examples of definite improvements that are not technically new functionality.
How did you extract concerns from class components and reuse them previously? Easy and hygienic extraction and composability of concerns literally is something new enabled by Hooks that was not offered by class components.
You're also misrepresenting what the docs say about replacing class components. They're saying that you don't need to replace class components just for the sake of using 'the new thing'. However if there was some concern you wanted to extract from a class component that you could not previously, you absolutely could adapt it to use hooks, and then extract and reuse that concern in another component.
> The docs actually state quite clearly that developers are discouraged from replacing class components with function components.
Could you link to where it says this? My understanding is that hooks are intended to be the new best practice, and ideally all code would use hooks (which the React team believes are overall better than class components), but the React team doesn't want to force migration pain on everyone. So as I understand it, it's not that a class -> hook refactor is "discouraged", it's more "don't let this be too much of a distraction, and don't feel obligated to rewrite old code".
React changed the way developers reason about UI/DOM from imperative to declarative, the holy grail here is that a declarative API allows you to move up your state and have a "single source of truth" and so makes it easy to reason about your application's state at the cost of having more plumbing, for example consider incriminating the value of an input with jQuery (imperative) vs React (generally with Redux).
What Hooks does is move the component's state management from components root a level deeper into hook functions and advocates for reusable state management functions that manages various fragments of your component's state, this I believe is a step backwards in terms of simplifying how you reason about state management in terms of complexity --not lines of code.
I am just not sure if this abstraction is worth it in practice and a good step for React.
I got the sarcasm, but comparing what Hooks brings to table to what React did is unfair. Hooks are moving around state management, React was a paradigm change.
I am stealing this thread as it seems to have a lot of really knowledgable people in here.
I understand basic javascript but I am not an expert and I had a discussion with a developer I want to hire for a new app I am doing, who said that there is no open source components (like quill) which easily allow you to have textformating (bulleted lists, bold, text size etc) and that it would have to be done from scratch) which sounded weird to me since I found a quill component.
But I am not a developer so I need to educate myself a little better. What's a good tutorial to get my head around how React works.
I'm going to wait and see for some production success stories become giving it serious thought.