Hacker News new | past | comments | ask | show | jobs | submit login
Introducing Hooks (reactjs.org)
501 points by sophiebits 4 months ago | hide | past | web | favorite | 296 comments



My gut reaction is that Hooks isn't the greatest addition to React. One thing I've always pitched about React is the clean and extremely explicit API (with `dangerouslySetInnerHTML` being my favourite example). The hooks API is taking the dangerous road down to implicitness and magic which can only ever mean bad things in my book.

It's really not clear to me how calling the setter for these individual pieces of state triggers a render. It seems the `useState` call is implicitly linked to the calling component no matter how far down the call stack (with only a linting check keeping the safety on this footgun). I was also surprised to see the concept of reducers making their way to the API. We're being told the "classes are the biggest barrier to learning React" yet the notoriously difficult concept of reducers has its own method. Don't get me wrong, I _love_ Redux however I'm not sure I can get behind the shade for classes.

I'll have to play around with hooks before I can make a final call though because I have the utmost respect for everyone behind this project.

An interesting observation: I think this is the first piece of API that contains the word "assumes" [1].

[1] https://www.google.ie/search?q=site%3Areactjs.org%2Fdocs+%22...


Have you looked at what `React.Component.setState()` actually does under the hood? The logic isn't implemented in `React.Component` itself - instead, it tells the core React rendering logic to queue up a re-render. The real work is all inside React's internals.

I agree that the `useState()` aspect _looks_ a bit magical, but it's ultimately doing the same thing that `setState()` does in the end. React already knows what component this is, and you're telling it to queue up a re-render for that component.

Also interestingly, it seems that `useState()` is actually a wrapper around `useReducer()`, and not vice-versa :)


The 'this' in 'this.setState()' tells react which component queued the setState. With the new API that information is collected by react through.. ehm.. some kind of magic.

I understand why the react developers chose not to make the component an explicit argument in the new API, as it would open doors to misuse. But magic never seems to work out in the long run, IME.


I'd agree it's "magic" in the sense that it's not entirely visible to the end user. But, the key is that React is _already_ tracking _which_ component it renders as it traverses through the component tree. It's just now also keeping track of some additional data as it goes through the process of rendering that component. So in that sense, it's not any more "magical" than any of the existing render algorithm.


The problem is that the hooks seem to be much more restricting than setState. You can `if (condition) this.setState({x: 1})` but you can not with hooks because React keeps track and doesn't allow you to break out of a very narrow usage.

Look at the rules from the docs:

> Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.

> Only call Hooks from React function components. Don’t call Hooks from regular JavaScript functions.

I think this will lead to junior developers to not understand the React framework but to just accept "the way to do things" and do what the docs say, without ever questioning anything.


I think those rules only apply to useState and useEffect themselves, and not to the setState function you get back when you call useState.


Yes, I think you’re right, there are different restrictions on when useState and setState, though it is worrying seeing confusion straight away about it.

I wonder about a case where there is an expandable panel in a UI, and when expanded it should fetch then display data from a web service. Easy enough to do with this API by splitting the content of the panel out into a second component, but it is going to be very tempting to wrap that useEffect fetch call in an `if (expanded)` condition.

On the other hand, there are lots of positives about this design too, the correctly written code does look very elegant and I can see it solving real problems.


As I understood it you should not opt-in to use state conditionally in your component but you can still conditionally set the state. That means you should not conditionally call `useState` but it is fine to conditionally call the `setState` returned by the `useState`. That is not different to how you would use state in a class based component where you also wouldn't attach a state `this.state = {...}` somewhere in the middle of its lifetime. The component has state from the beginning of its lifetime or it hasn't state at all. There is not such concept as "Now that you are expanded you will transform into a stateful component".


What is worrying about that useState/setState example? The person just didn't read the page properly, it's not an indictment of the API. Maybe give it a month or two before the claims about confusion, this was just someone skimming the page and missing some details.


I think the recommended pattern if you need a "conditional effect" would be to just move the `if (expanded)` inside the effect instead of wrapping it.


I think it's best to treat the various hooks the same as method definitions: you wouldn't conditionally define componentDidUpdate or componentWillUnmount in a class component. Instead, you would conditionally do something within those (always-present) functions. The same applies for these hooks.


I had this thought as well. Ironic isn’t it, given that the main reason for hooks is that “classes are hard”.


I'm unsure what's ironic about it. Hooks feel significantly easier to me than classes in a bunch of dimensions.

Classes come with a whole lot of syntax & concepts like constructors, instance vs class properties, autobinding, that are otherwise not used at all in React. They present barriers to optimizing code with compilers, and property names don't get minified.

Hooks are Just Functions though. They don't even have to deal with the most confusing aspect of functions in JS: "this"/calling context. You could easily consume them in ES3 by just not using array destructures and function keywords and it would barely get less readable.

Contrast this with classes, where new devs are often pushed to learn experimental and often-changing syntax just to avoid the awkwardness of working with the current specification for classes in JS. The following isn't allowed per the spec or any stage 4 proposal, but it's all over intro tutorials so that people don't have to manually bind methods in the constructor.

  class Foo { handleClick = event => {...} })


> I'd agree it's "magic" in the sense that it's not entirely visible to the end user.

I didn't dive into hooks to completely yet to have a proper opinion on it, but the primary disadvantage of "magic" is that the end user can not deduce what's going on just by looking at the code. If magic is therefore "only" restricted to the end user, that's not much of a restriction...


There's already so much magic going on in React's code base. For Fiber, they put the stack in the heap so they could go around the JavaScript call stack and schedule work as they see fit

The real magic is in traversal APIs, like Context


Oh absolutely - by now I have read through the docs, and as I mentioned at [1] as well, I'm even expecting hooks to do away with more magic than it introduces.

That said, my main point was that "it's only magic for end users" is not really a valid excuse :)

[1] https://twitter.com/VincentTunru/status/1055747566393085952


Agreed, it's not really a valid excuse. Hopefully a scheduler re-write comes along soon to alleviate those concerns. I absolutely share them; I can't read any of that code anymore


I’m guessing that React is keeping track of the current component instance that is executing when the hook is called, instead of JavaScript keeping track of what ‘this’ is bound to when ‘this.setState’ is called. One could say that both systems are “magic,” but it looks like the React team considers the behavior of ‘this’ in JavaScript to be a source of confusion for React developers.


Yes, yes, and yes.

You can see the current implementation in react-dom@16.7.0-alpha.0 - see https://unpkg.com/react-dom@16.7.0-alpha.0/cjs/react-dom.dev... for the actual code. Do a search for some of the effect names, like `useLayoutEffect()`, to see the implementation details.

React already knows which specific component it's rendering, regardless of whether it's a class component instance, or a specific function component. Looks like what it's ultimately doing is just tracking some additional metadata added to React's internal bookkeeping - search for instances of things like `workInProgressHook.memoizedState`.

And as someone who spends a large portion of my time answering questions from new React devs, I can confirm that the behavior of `this` in classes is an _endless_ source of confusion. Mitigating that is going to be a big improvement long-term.


I’ve seen this discussion pop up before in other frameworks I have used as they evolved over time. Interestingly enough my favorite framework went from being very magic to being less magic and more explicit and verbose. I liked it better when it was more magic.

Guess I’m in the silent group who isn’t bothered by a bit of magic, and actually likes it. Sometimes I don’t care too much what’s going on under the hood so long as I understand what to expect to happen. If it’s a good framework, magic or not, the documentation will do a good job of detailing how to use such magical features.


Magic is great when it works. The problem is when it doesn't do what you are expecting, it can be much harder to troubleshoot. (Did I do something wrong? Am I hitting a bug?)

Magic hides internal details, hence users are less familiar with them, hence they struggle more to diagnose when the magic fails to happen.


Don't want to be rude. But, the truth is, it is only a magic if you just can't figure out how they implement it...


The magic isn't what React.Component itself does, really it's the use of global variables (or close enough), because there is no other way in js to know inside useState what component called it.

The only way I can see this implemented is that when react calls your component function, it then keeps it a note of it in somekind of globally shared variable and then when useState is called it access that same shared variable to get the state.

It's also dependent on call order - that's a sure sign of magic work.


React has some knowledge of a given component through the use of `createElement` (or its JSX equivalents), so it's not even using global variables.

https://reactjs.org/docs/hooks-faq.html#how-does-react-assoc...

The "memory cells" the FAQ mentions sounds awfully like a map structure where React uses some internal identifier generated on first render to map any state handlers. The only "magic" bit is that it relies on the order of the `use` calls to be the same every time.


It is a globally shared variable.

Really either react notifies or registers the component to the module to exports useState, or more likely useState goes to some react internal api and retrieves the currently running component.

It's as much a global variable as the singleton pattern.


After pouring over this API for the last 3 days and keeping up with the RFC, I think I have reversed my position. I felt I couldn't leave this comment like this because it doesn't reflect my opinion anymore. I think hooks are amazing. If the React team can nail the API down, I think hooks will be revolution in how we work in React. I still feel like it will make the barrier for entry a little harder but as an experienced React dev, they're fantastic.


Agreed, the explicit nature of React is a really appealing aspect of the framework to me. Coming from Angular 1, React is remarkably "magic free," while offering a comparable level of functionality.


Agreed it’s implicit. I think it works by keeping track of start and end of Component rendering and counting the function calls to useState in between. You can imagine the following sequence of events.

- Enter Component A

- Use State A0 (does not exist, set default value)

- Exit Component A

Where calling setA0 sets the value at index 0 for Component instance A and queues render again.

- Enter Component A

- Use State A0 (has existing value)

- Exit Component A


i don't trust anyone who "loves redux"


> In our observation, classes are the biggest barrier to learning React.

As someone who struggled hard with some aspects of learning react, i felt this to be the absolute opposite. Watching people to combine and spread logic over dozens of functional components, and drag in other external libraries like recompose to do stuff like lifecycle hooks, and using HoC's, just to avoid classes makes my head hurt.

> Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.

I really don't like this, and to me this feels really finicky, and unfortunately the explanation doesn't make me feel warm and fuzzy ether. While it is great they are adding a linter plugin for it, i feel like this is going to be really easy to shoot yourself in the foot, and feels like it is relying on behind the scenes magic too much.


You also can call functions that call functions that set up hooks. What if those functions have control flow? Must we build linters that recursively taint any hook-touching code segments?

Since Fiber, React has become difficult to reason about. There is a stateful crawler that is going up and down and sideways in your hierarchy, running code with side effects and telling you that it will isolate those side effects. The golden brick road is surrounded by briars, because you cannot know the nuances of that renderer’s contracts, because you cannot read the code of that renderer, because it’s too dense to understand. I miss the days when React was a simpler “dive” than Angular in this regard, and I could boast about its simplicity. In the interest of efficiency, we have forgotten how to climb the walls of our garden.


>> React has become difficult to reason about

Absolutely. React started off simple but with things like Redux added on, it has become unnecessarily complex. The performance benefits of React is overrated. Javascript is so fast these days that you can rerender the whole page on navigation and no one will know the difference. I built a whole social network site based on a simpler alternative, UIBuilder, and you can see for yourself that it is performant: https://circles.app

UIBuilder is here: https://github.com/wisercoder/uibuilder


But they needed Fiber to make AsyncMode possible

And once it's well baked enough, it works very cleanly with universal rendering strategies. It means you don't have to separate logic into components where it doesn't belong because the server render ignores loading logic in componentDidMount. It's suddenly all first class

And, then, theoretically you can remove Redux and just use Context

It has gotten really wacky along the way. I hope they don't lose sight


I feel the same way! Maybe I'm just getting older, but I like code to be boring. A class is something everyone can read and understand. If you have to navigate a maze of HOCs withStateHandlers, enchancers, redux actions, reducers and connectors you end up needing to open 10-20 files and jump around between as many functions to build a picture of how a component works. Considering code is read more often than written - that seems like a huge step backwards.

Hi, I'm Dan. I write boring code. I love Go because it's super boring.

I like to read boring code, write boring code, and then get on with my day. I don't like long walks through the codebase trying to understand how everything is wired up in a super-cool functional way. Get off my lawn kids.


What's actually funny here, is that maybe you aren't old enough. The "Super-cool" functional way has been around as long as types and functions, Lisp and ML have been around since the what...50's and 70's respectively. Immutable state and referential transparency are boring. Get off MY LAWN kid!


OMG. I am Dan also. I am getting older also. I LOVE Go also! Too funny but we are living parallel lives. Now get off MY lawn!


> A class is something everyone can read and understand.

This is simply not true. Your post is very strange, you just assume classes are simple and boring but everything else is 10-20 files with fancy magic and blah blah blah.

The truth is that Dan is wrong about what makes code boring. Immutability is boring. Dan just likes Go.


A class has all the related code in one place in one file (some languages excepted, base classes excepted, but true enough for React purposes where inheritance hierarchies are quite limited and rare in my experience.)

I like immutability. It can make code easier to read and understand if done well. But within reason.

It's not that I'm creating some strawman where the alternative to a class is 10-20 functions across as many files - but that's actually mild compared to some things I've really seen.

To give an example, about a month ago I had to read a co-workers implementation of a feature and it was literally a maze of some 30 functions many of which returning closures, some of which return other closures. With state scattered all over in withStateHandlers, etc. I spent two hours on a Saturday trying to understand it and make the changes I needed to make before I gave up and assigned the ticket to my coworker who wrote it all. Basically he's the only one now who can modify that code easily (and incidentally he's away now on leave, if we have to modify that code again, we're screwed.)

So immutability of data is awesome. Immutability of code is not. If it was a couple boring classes I could have read the code and made all the changes I needed to make in less than an hour.

Simple an predictable and boring is fantastic where code is concerned. I love Go not because of the features it has, but specifically because it's limited enough that the code written in it is almost always easy to understand.


functional javascript can increase code clarity if written well. Certainly ramda is usually a huge improvement when making mutations in a reducer. compose()'ing a bunch of HOCs is essentially the same as having mixins (and it's exactly the same as @decorators), just with a slightly different syntax.

I think it's mostly down to the paradigm you're most familiar with. Classes are normal to OO developers, functional composition is normal to FP developers.


Mmm pointers.


Amen!


React is intended to be a view-only library but in practice people shove all their business logic in there, mostly because React makes it incredibly hard to do anything else. Because of this, innovations in React are going in the wrong direction. This Hooks feature is meant to solve a portion of this, but it's going in the wrong direction.

A better bigger-picture innovation would be to have a React-alike that is actually only the view layer, and makes it significantly easier to write your business logic using plain old JavaScript functions/classes.

Ideally it would have an API that encourages you to write your business logic as a hierarchy of state machines, because that's what apps really are. But the state management should definitely be done outside React, similar to what Redux has done, where your actual state is transformed into props and passed into React.

Also, screw you HN for always penalizing my account so that my content shows up at the bottom instead of the top and has no chance of being seen. My content is good, your algorithms suck.


> React is intended to be a view-only library but in practice people shove all their business logic in there, mostly because React makes it incredibly hard to do anything else. Because of this, innovations in React are going in the wrong direction. This Hooks feature is meant to solve a portion of this, but it's going in the wrong direction. A better bigger-picture innovation would be to have a React-alike that is actually only the view layer, and makes it significantly easier to write your business logic using plain old JavaScript functions/classes.

This. This is spot-on IMHO.


You can literally use React for JUST the view layer... you don't have to maintain any state inside react if you don't want to. Early on, many did use it for just a view layer.


> in practice people shove all their business logic in there, mostly because React makes it incredibly hard to do anything else.

I'm not an expert by any means, but I wrote a fairly substantial react app recently, and I found that redux not only made this straightforward, but made it hard to do anything else. I did have to learn redux and redux- saga on top of react, but it wasn't hard.


Just a FUCK-TON of boilerplate :P


You say boilerplate, I say simple declarative layout of the boundaries between UI, state and state transitions. :-)


People use the word "boilerplate" a lot, but everyone seems to have something different in mind when they say it. What specific concerns do _you_ have? I'm a Redux maintainer, and I'm always happy to try to help offer possible solutions.


I don’t really think there is a way around it if you go with the action/reducer/saga model.

I enjoy my code fairly explicit, so writing a button click that invokes some request has me writing:

- A click handler

- 3 new action name consts (request, success, failure)

- An action instantiation function that takes the necessary arguments for request.

- A saga function that catches these request actions, runs a request, and invokes the success action/failure action depending

- 3 handlers in my reducers. One for every action.

It all adds up if you have a ton of buttons :P


Sagas are a great power tool, but I personally wouldn't use them for most simple API requests, largely because of the need for "signal actions" to trigger the logic.

You might want to check out our new `redux-starter-kit` package [0], which can simplify some common use cases for things like action creators and reducers. There's also many other existing libraries to handle repetitive code like API requests as well [1].

[0] https://github.com/reduxjs/redux-starter-kit

[1] https://github.com/markerikson/redux-ecosystem-links/blob/ma... , https://github.com/markerikson/redux-ecosystem-links/blob/ma...


I think you need to use sagas for either all your logic, or none of it. Having it half/half just means you’re always searching for where something is located.

That said, thanks for the recommendations! I’ll check them out.


FWIW, I use sagas _and_ thunks in my own app, depending on what it is I need to do.

Also related, the new Redux FAQ entry on choosing between async middlewares: https://redux.js.org/faq/actions#what-async-middleware-shoul...


This is exactly the thing we need fixed. I get that Angular has one way of doing it, but I still feel like it's going in the wrong direction (too Java-like).


I agree. I feel using JSX for example to define application routes (a la react-router) or do any other type of non view logic is just wrong.


Well, you usually have more than one layer of state... a holistic application state, and a control/component state.

It's possible to completely separate out your state machine and use it separately from rendering... It's also possible to integrate it all. Best practices are generally somewhere in between and having your state where needed... if it can be contained, contain it... if multiple controls need it, globalize/context it.


React was never a view-only library.

Pete Hunt always said he saw React components as mini MVC modules.

it's even less true nowadays with features like Context or suspense to supplement the component states. Redux was kind of a temporary hack.


I distinctly remember the phrase "V in MVC" being prominently displayed somewhere on the official React website(s).

Found it: https://web.archive.org/web/20140329114924/http://facebook.g...

> JUST THE UI

> Lots of people use React as the V in MVC. Since React makes no assumptions about the rest of your technology stack, it's easy to try it out on a small feature in an existing project.

So I was mistaken. It didn't say that's what it's only intended for, but that's what many people use it for.

Either way, it's not great at the M or C parts of MVC. Context does very little to ease that pain. Redux was more manageable but also overly complex, but it's only React's design that forced it to be so complex.


But managing state is quite hard in general. Angular proudly advertises it solves all problems you can have on the frontend but I would take react state + utils over angular's magic templates, rxjs and bindings any day.


Right, and that's what I'm recommending we in general try to innovate on: better state management than React, but with the ease of writing view components that React has showed works well. Since the view is hierarchical, it makes sense for components to inherently also be hierarchical, but business logic often doesn't match up to React's component hierarchy, so it should not be done inside React or tied to React's hierarchy.


Out of curiosity, have you actually tried the latest version of Angular to see if your preference does hold up? It’s come quite a way since the bad old days.


I can't speak for GP, but have used angular up through 4.x (not quite current) and don't find it better than React's ecosystem imho.

With React I can often bring in additional components and libraries without friction. With Angular it feels like doing anything means significant friction. And heaven help you if you want to change the way something internal works, or work around things.


I can’t say I’ve had that much trouble bringing in third party libraries, nor have I had a need to change how the framework works internally. I think this is the same as with most frameworks, you tend to just use them rather than doing stuff under the hood. Can you give an example?


At this point not really... it's been over a year since I've had to really worry about it. It was better using angular-redux or ngrx, but still was a weird experience. When you have eventing issues with RXJS, or handling integration with other libraries, it's definitely not as broad or mature as the React space is. Anything from chartjs to color pickers, I'm trying to recall the last big issue I had in an angular app. In the end, I just remember pain all along the way more than most specific examples.

Oh yeah... drag-drop integration... that was the single biggest pain. None of the component libraries worked well, and doing it manually was harder than I've experienced before, including just straight JS, and definitely worse as a whole than using say jQuery-UI.

If it were a year or more ago, I could cite better examples of pain points. 2+ is better than 1.x, but still horrible. I'd rather see people adopt Vue over Angular. I still prefer a react-alike over any of them.


Funny you should mention drag drop, it’s now built in as of version 7, just released a few days ago. Look up the CDK for more details.

Whenever I’ve needed drag and drop functionality in the past I’ve found it in existing UI components. A fairly comprehensive one is primeng. I’ve also added an angular colour picker and highcharts without very much trouble.

Often when I hear people complain about angular, I wonder if they just don’t understand it very well and are trying to do things the wrong way. Angular is opinionated, but I don’t find it terribly difficult or painful, though at this point I do have rather a lot of experience with it and find it’s difficult to put myself back in the shoes of someone with less.

I really do enjoy the framework and how comprehensive it is. I like having a framework that gives me so much out of the box without having to go to a somewhat unstable ecosystem of related projects. Frankly I think Angular’s bad name is due in part to it simply being fashionable to put Angular down, and partially because it’s critics never really learned how to use it.

Also, something about jsx just rubs me up the wrong way.


I feel the opposite... I feel like React, by comparison, and JSX are much like the huge lego sets you used to be able to get generically... being able to plug in whatever I want. Angular feels like being stuck with a Duplo version of MindWorks.

As to JSX, it's something close to what I wanted a long time ago... when E4X was added to Mozilla's browsers, along with support for it with Flash/ActionScript3 and XML literal support in VB.Net (not that I love that language) ... interactivity to the UI was SO much simpler. The shame is it was never really supported in other browsers, which left it dead on the vine.

When JSX came out, it's REALLY close to what I already wanted, and in most cases better. In the end, I can compose a React/JSX component starting with a static render function in a file by itself... I can grow it and turn it into a class or wrap it in higher order components. Compose with extensions like react-redux, material-ui, react-jss with ease. Every single time I write an Angular component, I'm looking up configuration arguments for @directives. It's just painfully restrictive by comparison.

Simplest react component

    // HelloComponent.js
    import React from 'react';
    export default ({name}) => <div>Hello {name}!</div>


    // StatefulComponent.js
    import Hello from './HelloComponent.js';
    ...
       return <Hello name={this.state.name} />
That's off the top of my head... that's just the code you have to write... Now, do the same thing in Angular off the top of your head, I'm willing to bet it's a LOT more verbose, ugly and hard to remember/modify what you need.


I agree. Optimizing a developer library for developers who struggle to understand what a class is seems like a good way to build something very convoluted.


I don't think the issue is "what is a class". It's more that the lifecycle functions get tied into the class, and you end up with a ball of highly conditional logic. It's easy for newbies to just add stuff to make it work, but end up with a mess.

React is the view layer, so the class concept of "here's some data and methods to alter it" doesn't really match with what happens - I don't know that components every should have been classes in the first place.


According to the article yes, the issue is "what is a class":

"You have to understand how this works in JavaScript, which is very different from how it works in most languages. You have to remember to bind the event handlers." etc.


Eh, even in the same paragraph it says "The distinction between function and class components in React and when to use each one leads to disagreements even between experienced React developers."

Also, bits of class issues show up in the other complaints.

So, no, it's not just "what is a class" and it's a weird hill to die on. I feel like most of these responses to hooks in general just focus on the most trivial detail aka bikeshedding.


I'm focusing on classes, because it seems to me that to "React" classes are a necessary evil (or they are treating them like they were).

Hooks, suspense, context wormholes - I'm not sure if these features should be part of a view engine. React, to me, did one thing and did it well, but now... I don't know.


Can't argue with the text of the article. I do, however, stand by why _I_ have found that classes are a bad match for this need, and watching the video of the demo did a much better job of suggesting the benefits and reasoning...reasons that don't really match the parts of the article you've quoted.

https://www.youtube.com/watch?v=kz3nVya45uQ&t=39m (from elsewhere in the comments here)


>Video unavailable. This video contains content from WebTVAsia (Music), who has blocked it on copyright grounds.

LOL, did they just block a video presentation for some incidental random music in the background?


It's not just having to understand what a class is, it's also having to know and remember to add a constructor to your class just to call `this.handleSomeEvent = this.handleSomeEvent.bind(this)`.

Sure, I know what it does and why it is needed, but it is ugly, cumbersome, and I keep forgetting it nonetheless.



There are other ways to approach an issue beyond shoving everything into a class. I'm not sure I really like the new hooks over the state methods at that level since I tend to separate global state (redux) vs component state (class) vs component state rendering (functional component).

In the end it depends on your style. I think this might be useful in a way that can be more pure than some other methods might be.


I don't know what you mean by pure. There is nothing reverentially transparent about the new API. (Nor can there be, really.)


And nothing that requires you to use the new API.


I can see both sides. I teach React to newish coders, and classes are easy for them to grasp...and then immediately create labyrinthine monoliths. At work where I do React, we emphasize small components with limited and segmented logic (ideally pulling as much logic out of the React parts as possible - and this is most easily done by avoiding classes).

At the same time, I've a passion for trying to make code more maintainable - which often means avoiding too much abstraction and keeping logic plain and up-front, where it can be found and followed, so I share some of your concerns.

But I'm excited about this. One of the best parts of React has been that the same logic that makes a good program makes for a good react app. Treat your components like functions (regardless of whether they are classes or not) - small, single purpose, decoupled from state - and you'll have an easier time. Hooks look to help that.


I can see both sides. I teach React to newish coders, and classes are easy for them to grasp...and then immediately create labyrinthine monoliths.

To be fair, that's pretty much what happens to all newish coders who are learning classes. Learning to use classes responsibly is really just part of the learning, though that seems to be the part that instructors pawn off to the next guy.

Once you learn how to use them judiciously, classes become extremely useful tools for encapsulation/abstraction where you need encapsulation/abstraction.


Maybe newish coders should learn the language they are using.

And of course there is typescript (and a gazillion of languages that can be transpiled to js these days), which synergizes very well with enterprise people and java/dotnet devs who never did a line of frontend before.


Maybe newish coders should learn the language they are using.

It's not a language thing. OOP discipline is a coding thing in general.

And of course there is typescript (and a gazillion of languages that can be transpiled to js these days), which synergizes very well with enterprise people and java/dotnet devs who never did a line of frontend before.

You sound like you don't actually understand why people like Typescript, or, more specifically, static typing.


> You sound like you don't actually understand why people like Typescript, or, more specifically, static typing.

Eh, in my experience, there are two types of Typescript users: 1) those users who appreciate the safety that type systems provide when used properly, and 2) those enterprise users of the language who have mostly only coded Java and C# and who like Typescript because it lets them write Java-style code for the browser.


Typescript doesn't do anything ES6 & Webpack don't already do; Javascript already lets you write Java-style code if you really want to.


Typescript significantly predates ES6 and Webpack. Java developers have been drawn to Typescript for over 5 years now.


I know, but lately during frontend interviews I was surprised how many times I met with "I'm a developer I can do anything" type interviewers - some of them were dotnet, others were java devs and they preferred typescript, because 1. javascript is a terrible language 2. with typescript they feel right at home 3. they can use a "proper ide" (please, don't ask, I already had an argument and a rejection when I tried to ask about webstorm)


I "don't actually understand why people like Typescript", or lemonade, or skiing, or eating fish. I know why I like it, including static typing, and how I can find a balance with using its features (and not using some).

On the other hand I'm not trying to hide that I'm bitter about the mental lazyness around typescript - I had some bad experience with interviewers who praised ts (without ever bothering to learn the core principles of javascript) a bit too much for my taste (but again, this may just be dismissed as anecdotal evidence, which it is).


You wish we went back to bind and apply? And not being able to trace logic, state, and DOM through a labyrinth of Backbone views? We have come so far

How is static typing "mental laziness"?


The article says bind as a negative point - I perefer the new non-bound class method syntax:

``` private handleClick = (event) => {} ```

By "mental lazyness" I mean that people (as in people I have met with) piss on javascript and praise typescript and in the process they never bother to learn about javascript.

I do like vue, react, angular of course, but I don't think that you become a frontend developer from one day to the next and keep saying that typescript is _exactly_ like java (or dotnet).


So you involved yourself in a faction war because of... some things some interviewers said? Please, spare us next time.


> and using HoC's, just to avoid classes makes my head hurt

I don't know if it's just something I don't see that often and aren't that familiar with, but I also can't stand the overuse of HoC's for this purpose. Seen some very clever and very, very unreadable HoC's so far and I hate working on codebases that use them liberally.


I think it depends on the use... I think some can be ugly... right now react-loadable and a custom InRoles component are the two I'm using the most. One is for loading state and code-splitting, the other is for allow/deny state...

    <InRoles roles={[...]}
             allow={() => <Component ...props />}
             deny={'/route' /* or a render, or skip */}
    />
InRoles works for a router redirect, displaying alternate content or no content.

In the end it depends on what you're trying to accomplish. HoC's are pretty useful. Also, it really helps in terms of unit testing your more functional components.


I think the HoC's that get me the most are the ones written by JS devs who think 100% functionally. Actually a lot of the hard ones to grok were written by Jason Miller of the Preact fame, who seems to think out JS in a minified, functional fashion. I've had to step through and re-write several things just to see what was actually happening, then pare it back to it's original form before I "get it". It's super clever, but man did it take me a while to distill it's logic.


While I do agree that higher order components are not the most beginner friendly pattern, to state that they are being used just to avoid classes completely misses the points of why they are used. They are a functional pattern that help one create pure components.


Yup! they can be tested separately and introduce a separation of concerns that is much better than a "simple" class that "just has everything in it". (Which usually leads to mounds of copy-paste code)


(I work on React.) I think we’re on the same page here. Having a pile of recompose helpers and HOCs is exactly what we think/hope Hooks will help avoid.


> i felt this to be the absolute opposite

I completely agree.

When I started using React a couple of years ago, the only thing that made sense were the classes.

The bad aspect about React and JSX is that in general there are way too many JS acrobatics which alienates everyone from the codebase who isn't a JS ninja.


In my experience classes are one of the few boring, easily understood parts of react for almost everyone I mentor/work with.


I went from skeptical to sold in five minutes. This API is absolutely beautiful. I have quite a few components in each of my projects that do nothing other than call lifecylcle methods (they render `props.children`). Composing them is sometimes easy, and sometimes awkward. Especially when trying to read a value back from a child component.

With the hooks API, that child component can be rewritten as a simple hook, making it much easily composable.

Thing is, hooks are very simple, and some of them (except `useContext()`) are expressable with react's current API. I'm surprised that none of us thought of them earlier.


Agreed. Having used React since the beginning and having taught it, this seems to me its natural evolution. I also thought the API was beautiful. I also think it will be easier to teach, but I'm less certain about that.

While I think its a great API, I totally understand some of the hesitance expressed by others. Its more churn, etc., it seems to allow for more spaghetti code for intermediate devs perhaps. But, I don't mind the churn, to me, while its been a nuisance, it also often appears like an evolutionary process.


> I have quite a few components in each of my projects that do nothing other than call lifecylcle methods (they render `props.children`)

I have a few of those too, but I feel like ES7 decorators already solve this problem quite well (e.g. [1]). But I guess hook will generate better code for prepack than decorators will.

1: https://medium.com/@jihdeh/es7-decorators-in-reactjs-22f701a...


Looks like the default way of writing react components in ClojureScript (with Reagent [1]). Compare:

CLJS, Reagent:

    (def click-count (r/atom 0))
    (defn counting-component []
      [:div
       "The atom " [:code "click-count"] " has value: "
       @click-count ". "
       [:input {:type "button" :value "Click me!"
                :on-click #(swap! click-count inc)}]])
JS, React + Hooks:

    function Example() {
      const [count, setCount] = useState(0);
      return (
        <div>
          <p>You clicked {count} times</p>
          <button onClick={() => setCount(count + 1)}>
            Click me
          </button>
        </div>);}
Not sure about the name "hooks". Trying to figure out why they name them like that.

1: https://reagent-project.github.io/


I don't think it's quite the same, is it?

In the Reagent example, you declare the atom outside of the component function, and that atom would end up shared if there were multiple instances of the counting component.

In the react example, each instance of the component would have its own separate state.

Reagent will let you put the atom inside the component, too, so you can do something very similar to the React example. Just wanted to point out that the two examples you've got now do different things.


hmmm yeah here's a better example:

    (defn timer-component []
      (let [seconds-elapsed (r/atom 0)]
        (fn []
          (js/setTimeout #(swap! seconds-elapsed inc) 1000)
          [:div "Seconds Elapsed: " @seconds-elapsed])))
Now the atom is defined inside the component function, and is captured by lexical scope in the returned function. Any timer-components on page will have their own `seconds-elapsed` state.


This was such a common pattern that reagent created a macro for it. But I like the macro-less code, in that it becomes very clear what is happening. A good macro reduces complexity by making code concisely simple. A bad macro hides complexity by making code easy to write.

Frameworks like React succeed when they are built like a good macro.

In this case, React is both hiding complexity (component lifecycles) while adding unnecessary complexity (a lInter that will inevitably fail). It’s odd to see React make this move, but not surprising considering that it now has a larger use-base then ever before.


Are you maybe talking about with-let? I'm fairly new to reagent and not really familiar with any of its macros

As it turns, there are only 5 macros, and only a some of those seem to be part of the public API, which is how I found about `with-let` :-)

https://github.com/reagent-project/reagent/search?q=defmacro...


Yep. It looks like React is eating Reagent's lunch and I'm super excited about it!


This is a bizarre comment to me. React is already used _way_ more than Reagent. Even Reagent itself uses React internally. What "lunch" is there to eat? People who enjoy ClojureScript will still use Reagent/Re-Frame because it's not JavaScript.


I think it refers to adopting a pattern from Reagent.

Throughout its lifetime, React does seem to have had a mutually beneficial relationship with the ClojureScript ecosystem, with select ideas from Reagent, Om and others being adopted in core React, or as JS libraries around it.


In the small world of the CLJS ecosystem, we use some very elaborate wrappers around React (for good and bad reasons). I'm excited to have many of the features we have had to implement and maintain in user land be moved into React proper, so that we can remove swathes of code that were filling in gaps in the React framework.

In general, I am much more confident in the React team supporting these concerns - simply because there's WAYYY more time, money and mindshare involved - than the CLJS ecosystem shouldering the burden.


Unpopular opinion: There are too many cooks. I used React two years ago because the API was tiny, simple and elegant. They are adding new API features left and right, and the framework feels very uncoordinated now. The surface area is way bigger than it needs to be. This is my cue to finally explore other frameworks.


I tend to agree, but you don't have to move at the same speed as the framework. If you have a version that is working well for your needs, stick with it for a year. Then decide when and where to upgrade. You can let the dust settle on new features, let other people learn the harsh lessons and come up with best practices, and then you follow in their footsteps, stably upgrading your codebase to exactly the point that makes sense.

Or, if you prefer a business cliche, prefer leading edge over bleeding edge.


I agree with you, but I've also tried other frameworks and there isn't a single one that is all-around better than React.

Unless you're willing to migrate to other compile-to-js languages.


If you aren't interested in 3rd party components or React 16+ features... you could try Inferno or Preact as alternatives with JSX and a similar API.


Have you tried mithril.js?


es6 (with babel) is already effectively a compile-to-js language


"You might be curious how React knows which component useState corresponds to since we’re not passing anything like this back to React. We’ll answer this question and many others in the FAQ section."

While I appreciate the functional usage of state, this type of magical behavior worries me a bit. Wasn't more straightforward semantics possible (even if the syntax wasn't similarly straightforward)?


This is where I'm falling on it. What started as initial excitement over a lens-like addition started to feel more like black magic once I realized that it relies _a lot_ on implicit ordering just to preserve a seemingly simple usage pattern.

While it may _look_ nice to be able to just call `useEffect` and have it infer the rest, it just ends up masking the flow of a hidden parameter into that component, and convolutes the user's understanding of what React is actually doing.


I think people are getting too hung up on the "implicit ordering" thing. The only thing that really matters about the ordering of hooks is that the call pattern remains stable between render passes. This code:

    const [foo, setFoo] = useState("abc");
    const [bar, setBar] = useState("123");
...is functionally the same thing as

    const [bar, setBar] = useState("123");
    const [foo, setFoo] = useState("abc");
The feature is _declarative_ in the same way element rendering is declarative.


Couldn't useState accept a name? How would React DevTools or another debugging tool know the name of a piece of state?


I'm at ReactConf right now and I've been asking everyone this exact question.


Component lifecycle methods are easy to grasp conceptually. At different stages of rendering the component, React will call one of these methods. Easy.

With `useEffect`, I have no idea what is actually happening here, and I've tried re-reading it a few times.


They're easy to grasp conceptually, but they're a pain to use in practice specifically because they force you to split up code which is conceptually related. I've had to deal with some truly monstrous class components in the past which would have been a hell of a lot easier to deal with if we had this.

As for `useEffect`: think about the kind of logic you'd put in `componentDidMount`, `componentDidUpdate`, and `componentWillUnmount`. In CDM, we set up side effects, in CDU, we update those side effects if needed (based on the props, state, and context) and in CWU, we clean up those side effects. If we squint a little, though, we're really only doing two actual operations in those three steps:

didMount: perform side effect A based on props/state/context didUpdate: clean up side effect A, then perform side effect B based on props/state/context didUpdate (again): clean up side effect B, then perform side effect C based on props/state/context willUnmount: clean up side effect C

So the idea here is:

    const [name, setName] = useState("world");

    function modifyTitle() {
      document.title = "Hello, " + name + "!";
      return restoreTitle;
    }

    function restoreTitle() {
      document.title = "Untitled";
    }

    useEffect(modifyTitle);
When this component is rendered, it'll run `modifyTitle` on the first pass, and store its return value (`restoreTitle`) for later. When it's rendered the _next_ time, it'll call `restoreTitle` first and then `modifyTitle` again... which itself returns a new "cleanup function".

So we basically have the same sequence of calls as this is mounted/updated/unmounted:

perform side effect A cleanup side effect A, then perform side effect B cleanup side effect B, then perform side effect C cleanup side effect C

The only difference is we never told React _when_ to perform these steps, just _that it should_ perform them at the appropriate time.


In the keynote, Dan talked about how this works. It depends on the order that useState is called, which makes conditional branches a no-no (there's a linter for it).


Since JS is single threaded, they are basically keeping track of which component was last called for render - that way they know useState() calls attached to which components. If the order changes, then they can't keep track of the different objects tracked by useState. So treat it like you would class state - all fields are always there, no matter which functions or conditional branches you take - hence - do your initialization above all your conditionals and loops.

Edit: And yes, slight concern of course, it's the got some rough semantic equivalents to a thread-local in Java, albeit in Java the danger exists downstream, this danger is only exhibited during initialization it seems.


IIUC, the order isn't used to figure out which React component is being rendered, but which of potentially several hook invocations within that single component is currently being invoked. If every unique hook could only be (directly or indirectly) called a single time per component, then there wouldn't need to be this ordering restriction. (Or more realistically, if each hook call also took an ID that is unique per-component.)


Just looking at the code I came to the conclusion it had to work that way, I don't like it, way too easy to break and some people are going to be very confused when things goes wrong. It's a uncommon/unfamiliar coding constraint. If you have to declare them all in the same order every time, you might as well force a single state (like the setState API) and/or keyed state values and have a safe API.


It'd be really great for VDOM, builder APIs, and any immediate mode -> retained mode mapping, to be able to get the _callsite_ of a function invocation. Then they could associate state with the callsite unambiguously without resorting to tracking invocations on a stack and disallowing control flow.

Tagged template literals already give us something of a callsite, since the template strings object is cached per callsite. You could do something ugly and use that to associate state:

  const state = useState``();


I don't think this will work, when I just tried to add a property in a template function I get:

    TypeError: Cannot define property foo, object is not extensible
Cool idea though


You don't add properties to the strings object, but use is as a key into a WeakMap.


The strings object doesn't seem to differ based on call site.

    > f = l => l
    [Function: f]
    > f`hi` === f`hi`
    true


What JS VM did you use? Edge/Chakra has a bug, but it's been fixed. That expression should return false in Chrome, Safari and Firefox.


> React assumes that if you call useState many times, you do it in the same order during every render.

Note they also say:

> We provide a linter plugin to enforce these rules automatically.

Makes me feel a little better.


I doubt the linter will enforce the same-ordering, that would require state between runs. I think the linter just ensures hooks are run at the top level in the functional component.


And it wouldn't need to. You're free to move around calls to useState() to your heart's content in your code, you just need to call them in the same order during the lifecycle of your component.


Why couldn't one just pass in `this` to useState, a key, or something similar?

Like, if I have two state variables, pass in a name for both, instead of relying on the order being the same.


It's meant for functional components, not classes.


"This" existed in javascript long before classes. No idea why my relevant question is down voted.


"this" isn't bound in functional components because there's nothing to bind it to.


Not in arrow functions, which are very common and any solution should certainly contemplate them.


This doesn't answer the question.


And what would `this` be in that function?


There are a lot of gotchas with these. Don't call in conditionals, branches, loops. Can only be called from function components. Order of invocation matters (yeck!)

If the goal is helping developers "fall in to the pit of success" I think classes are a much better option than this.


There are a lot of gotchas with the object-oriented way of doing these things too. Don't set `this.state` directly, don't forget to keep your side effect logic in `componentWillMount` parallel to your cleanup logic in `componentWillUnmount`, et cetera.


Yep, no doubt. The problem is they aren't getting rid of old foot guns, just adding new ones. And the new way with hooks isn't obviously superior to the old way (debatable to be sure, but with all the constraints hooks are not a broadly applicable solution to many problems). So now you've got two separate but equally powerful guns pointed at your feet.

Is that progress? I'm too old to think so.


Inl don't understand why they don't use a second parameter to mark the calls.


If you don’t put this in conditional, branches or loops, by definition they will always be called in the same order.


yep I see nothing wrong with classes, infact I think I'm going to go back to an older build of React. All this suspense, the messy fiber rewrite and all is just screwing up library.

LONG LIVE class based component, there was nothing wrong with them. Don't fix it if ain't broke.


Good thing then that, as the page says, "There are no plans to remove classes from React.".


If an older version of react is the goal, maybe infernoJS would be the ticket. It's way more performant than most versions of React while being mostly API compatible (not sure about the most recent react changes).


I know I may be in the minority here, but I can't say that I'm a fan of this feature. I can't envision a scenario where this would be my preferred solution to any of the problems that they detail. Templates should remain stateless, as they are far easier to reason about that way. My gut reaction is that this is a giant step backward.


react is not based on logicless templates. Their very first presentation in 2012 or 2013 made that clear. It's a feature.


Why would this result in templates becoming more stateful? This is simply an alternative, more flexible way to build stateful components.


Are you referring to hooks in general, or the specific useState hook they showed?

I love the idea of hooks - the more I can isolate my logic, the better. The useState example I'm pretty ambivalent about, for the exact reason you state.


Am I getting this right: it’s an implicit global stack for the render loop? Sounds like a combination of the worst design features of OpenGL and Forth, to be honest...

OTOH, React has been pretty good about taking discredited design ideas — like Adobe Flex’s style of mixing XML declarations into ECMAScript code — and injecting them with new vigor. So maybe this one too is better than the initial impression.


Suspense is also based around throwing promises. React isn't afraid to go against the norm. So far they've been pretty successful, willing to give the benefit of the doubt.


Personally, I loved Flex’s mxml/actionscript combo. Its main (fatal) flaw was targeting the flash player. At the time, moving to html/js felt like a big step backwards on developer experience.


Yeah, MXML (and in fact most of Flex) had a lot of good about it. “Discredited” was too strong a choice of word in my post — I meant something closer to “unfashionable”.


God yes. In many aspects writing AS3 apps was so much better than writing modern JS.


While I agree that class components has always felt like a workaround to bypass the limitations of function components, and that it's obviously annoying to rewrite a function component to a class component just to add a state or a lifecycle method, the following explanation sounds a bit silly to me:

> In our observation, classes are the biggest barrier to learning React. You have to understand how this works in JavaScript, which is very different from how it works in most languages. You have to remember to bind the event handlers. Without unstable syntax proposals, the code is very verbose. People can understand props, state, and top-down data flow perfectly well but still struggle with classes. The distinction between function and class components in React and when to use each one leads to disagreements even between experienced React developers.

A framework shouldn't be designed around the fact that people don't know the language they are using, right?

Anyway, those hooks look like a good way to solve the issues listed above. Can't wait to try it out!


In the live talk, Sophie also discussed how Javascript classes are difficult for machines: minifiers aren't able to shorten the names of methods (because it's apparently hard to work out all the ways that the method could be invoked), and they cause stability problems with hot code reloading. So there are benefits beyond ease of use for humans.

(Also, I'm pretty fluent in Javascript and I still forget to bind event handlers all the time, which suggests to me that it's a counterintuitive pattern even if I know "how it works" on a technical level. And you either have to put a bunch of "this.handler = this.handler.bind(this)" in the constructor, or rely on class properties which are an unstable syntax feature, both of which are suboptimal.)


It may have been on purpose (came off as a sincere mistake), but Dan Abramov forgets to bind them in this talk while giving an example. It's a very common problem, even for the authors of React itself :)


It did come off as a sincere mistake, but remember, they had a dry run of the talks a day or so before. So could have easily been staged. But was hilarious anyway.


> because it's apparently hard to work out all the ways that the method could be invoked

Simple example case of a statement that makes it impossible to minify function names:

    class Test { static func() { /* function code */ } }
    test[prompt('function to call')]()


Doesn’t that example also make it impossible to minify the names of anything? Perhaps other than JavaScript modules, since AFAIK the popular module builders like Webpack do compile-time module importing (I believe that even the dynamic import function is recognized at compile time and doesn’t support throwing in a prompt).


No, that issue is unique to class/object property names. You can't dynamically reference a variable in a scope by name supplied by a variable in the same way (except by using `eval`, which does in fact cause minifiers and javascript engines to disable a bunch of optimizations in the scope it's used).


Of course it's unintuitive. I see dev veterans make the mistake all the time.

JS was so poorly designed. An implicit (not passed as an arg), dynamic this parameter. You couldn't be more cheeky than that really.

something like console.log.bind(console.log) is beyond silly. It's what we're stuck with but I will minimize the occurences of that kind of crap any single time I can.


You can just do `onChange={() => this.handler()}`.


This would create a new inline function on every render though, which potentially might cause rendering performance issues.


The Hooks way creates a lot of inline functions on every render.


Hardly ever.


>A framework shouldn't be designed around the fact that people don't know the language they are using, right?

No, but it could be designed around the fact that some of the language features are confusing or crap.


At the end of the day, the framework that allows people to get more done with less thought is going to win the most mindshare.


That is unfortunately not true. The framework with the best marketing will win.

That's why frameworks like angular and react are so popular. Both are designed to work well in large teams that work on huge codebases. Most of us probably would came along with much much simpler solutions.


So are you telling me Facebook has a serious marketing budget for React? If so, that means tech has gotten way way crazier than I could ever have imagined.

There's a complexity angle that needs to be appreciated. I love Rails, I think it's the best solution to the problem it tries to solve for the people it wants to solve that problem for. But it's been called overly-complex and magical. But less-complex, less-magical frameworks just don't solve the problem as well. Just try building something big with Sinatra and you'll see what I mean.

I'm not terribly familiar with Angular, but React, when you remove it from its ecosystem and treat it as just a library-framework, does a great job at facilitating the building of user interfaces. The abstractions and underlying paradigm are somewhat hard to grasp, but once grasped, a competent architect can lay down patterns that juniors can implement.

A lot can get done in a small amount of time with React. The people that managed to do this in the beginning are the ones who christened React the Son of UI Development. People listened, and now we have the Church of React, with the Redux Reformation now upon us. Facebook had nothing to do with it, that was all us.


Another great option to bypassing the limitations of functional components is using a higher order component library like recompose[0]. Does have somewhat of a higher learning curve, but I personally consider it a must have tool on all my projects.

[0]: https://github.com/acdlite/recompose



To be fair, JavaScript has been a moving target and things like classes are quite new. Then again, it doesn't make sense to avoid features just because they're new.

I think the point is that they want to provide two ways to do simple things: classes and functions. Functions have better performance, classes are more flexible.


>I think the point is that they want to provide two ways to do simple things: classes and functions.

At the risk of seeming like an old man complaining about new things, what problem would "classes" solve in javascript that the existing object syntax, which allows for inner functions and variables, doesn't?


Prototypal inheritance, and scope controls more refined/easier to work with than IIFEs. In the end the class notation is "simply" syntax sugar giving the object syntax the benefit of Function.prototype and IIFE closures, without having to resort to layers of either/both.


This is really interesting. I'm a big fan of any abstractions that reduce the amount of code I have to write. Just a personal preference. Other programmers like to avoid "magic", but I love it.

`useEffect` feels much cleaner than the component lifecycle methods, and I could add some abstractions on top of those. e.g. a higher-order function that adds/removes a window event listener, and you can just pass the event and your callback.

Maybe `useState` could take a second argument that gives the state a "key", so that it can be called in any order. I can imagine breaking up the `useState` calls into different functions, and then skipping one of the functions if something changes. So it might be handy if there was an escape hatch where you could label each call with an integer or a string.

EDIT: Wow, it would be awesome to use this pattern for my Redux reducers. Instead of having to connect up all the actions in my container and then prop-drilling all of the dispatching functions down into my components, it would be great if I could just import the action creator directly and use it anywhere I want. Maybe I could add some similar hooking magic to find the store from the Provider and call dispatch with the action, instead of manually wiring everything up. Although actions are usually called after the render is finished, in onClick handlers, etc.

Or maybe I could do this with Context. I'm just really tired of prop-drilling all these action dispatch functions down to my components. There must be a better way to automate all of the boilerplate with actions and reducers, even if it's a Babel plugin.


Hi, I'm a Redux maintainer. If you've got some suggestions on how we can improve the API and usage, please file an issue!

I'm currently looking at revamping our WIP React-Redux v6 branches to use hooks internally. Looks really promising so far, but I'll have to keep playing with it and see how it turns out.

Our goal at the moment is to publish React-Redux v6 that is basically API-compatible with v5, and then open things up to discussion about potential alternative API approaches for a future v7.


Hi, thanks for your reply! I've had a look at some of the higher-level abstractions for Redux [1], but none of them really appealed to me. I'm just looking for something magical and opinionated so that I can write less code, so I might even try to write my own abstraction. I want to see if it's possible to automatically generate actions and action creators just based on the reducer. Maybe a special way of writing reducers, or maybe leverage the type system and write a babel plugin.

[1] https://redux.js.org/introduction/ecosystem#higher-level-abs...


Funny you should mention that :)

There's a lot of existing libraries out there that will indeed generate action creators, reducers, etc (see my Redux addons list [0] for examples).

One of the most interesting ones I've seen is Eric Elliott's `autodux` project [1], which does some clever bits of handling inside a `createSlice()` function.

Earlier this year, I put together a new project called `redux-starter-kit`] [2]. Its goal is to simplify several common use cases with Redux usage, including store setup, reducer definitions and immutable update logic, and default behavior out of the box. While we don't plan to add these things to the Redux core itself, `redux-starter-kit` is an official Redux-branded library, and we're going to start encouraging that people use it in most situations.

We just added a `createSlice` function to `redux-starter-kit`, based on the `autodux` approach. I'd encourage you to try it out, as it does _exactly_ what you're asking for. I'd also really appreciate some feedback on how well it works, and any additional ideas for things the starter kit should include!

[0] https://github.com/markerikson/redux-ecosystem-links

[1] https://github.com/ericelliott/autodux

[2] https://github.com/reduxjs/redux-starter-kit


autodux looks amazing, thanks for the link! I hadn't seen that before, and that's exactly what I'm looking for. Looks like there will be a bit of work to add support for Flow and Immutable.js, but I might look into that.

redux-starter-kit looks great too!


Sure. Also, just as an FYI, because a large number of people aren't aware this is possible: you can pass an object full of action creators to `connect` instead of a `mapDispatch` function. This simplifies the use of `connect`, like:

    export default connect(mapState, {addTodo, toggleTodo})(TodoList);
We're about to add a whole big section on dispatching and action creators to our new React-Redux docs site at https://react-redux.js.org - keep an eye out for that. Until then, check out Dave Ceddia's post at https://daveceddia.com/redux-mapdispatchtoprops-object-form/ for an explanation.


Whoa, I just found this redux-auto [1] project, which is a really interesting approach. You just apply it as a middleware and then you can import and call actions from anywhere. The API is a bit ugly but I like the general idea.

[1] https://github.com/codemeasandwich/redux-auto


Why not support Hooks in classes as well? The motivation is correct in that Hooks can help separate intertwined concerns that are currently mingled in the lifecycle calls. There seems a good usefulness in allowing the same cross-cutting inside classes as well as functions.

It would also presumably help avoid a "fork-the-world" situation where projects eventually find themselves having to maintain both HOCs and Custom Hooks side-by-side permanently as the userbase forks camps between the two. Potentially causing a maintenance hazard.

Certainly you can use one from the other one in component nesting, but particularly in cases where maybe a class has an inconveniently complex structure today, being able to refactor say all the state handling code to use hooks without having to refactor all of the side-effect handling code at the same time could be crucial for some projects in adopting Hooks.


I’d say the useState hook should receive a name parameter first and not depend on the call order. That way one can do branching, loops etc. This way it feels like too much magic.



This looks like a nice but not enormous improvement to React.

First, I really like how these hooks are optional. You can still use the current class-based mechanisms wherever you want. Existing code will keep working the exact same way.

For the specific hooks they provide:

`useState` seems like a slight improvement over using `this.state`, at least for simpler use cases. You save about 5 lines of object-oriented setup, which is nice. You also avoid scattering your code all over the place - you can now initialize your state variables in the same place you are using them. The only downside I can see is that if your initial state is constructed in a complicated way, `useState` doesn't seem to make it easy to do that only once. When you state is just initialized as 0 or null it's fine.

`useEffect` looks a little confusing because it is passing a bunch of anonymous functions around. It seems like a slight improvement if you have a lot of side effects that need cleanup, because you can put the code in one place instead of several different functions.

Hard to say how useful custom hooks will be. It might be easier now to put functionality that uses state in third-party libraries. For example, this `useDragGesture` hook: https://twitter.com/grabbou/status/1055521332031512576

The last thing that seems clear is that React embracing more of a "functional programming" direction. I think some people will like this and some won't. The nice thing is that you don't have to go all one way or the other - this change seems like it is really about making all of React's features available if you do want a functional programming style, since all of these features continue to exist in an object-oriented style.


I can see the benefit being enormous if you use typescript. Currently it is often a struggle to come up with the magic combination of generic parameters and HoC ordering to make things work, which might still fail if your HoC has an incomplete typing specification. Using a couple of very simple easily typed functions makes things much easier to reason about and to specify correctly.


This was one of the first things I thought about when I read the docs. This is primarily meant to replace render props and HOCs, which solve a legitimate problem but are a royal PITA to use, especially with Typescript.

This is going to make it about a million times easier to use Typescript with React.


I have some troubles with the state hook. It may look nice to a novice developer, but when I look at it I just see confusing magic. I read what's happening and I just say wait, there's no closure or class here, how this state is stored is completely hidden from me.

I can see uses for the other types of hooks, but the state hook seems like it would be much better served with an HOC like Redux's connectToStore, which would be concise and non-magical.


I agree. Something about it just doesn't feel right to me. Like state is stored in a global singleton somewhere.

Any of the examples touch on testing components using hooks? Any chance using the same component across multiple tests would result in state collisions? Especially when testing something asynchronous?


This looks like unnecessary magic. Classes are a core programming concept and this seems to be trying to get JS devs who didn't deal with them before to try and learn something else, while being completely non-transferable to any other language.

Making the built-in state management functions simpler would be better, as well as using newer JS constructs like decorators (aka attributes) to wire things up declaratively. MobX has been leading the way here for awhile with a very smooth dev UX that's even better than this Hooks proposal.


>Classes are a core programming concept

While I don't disagree with this, classes in their current incarnation were shoehorned onto Javascript's prototype-based object inheritance mechanism relatively recently. Javascript classes have enough idiosyncratic behavior that half of what you learn is essentially one-off, inapplicable elsewhere.

As mentioned in the "motivation" section[1], binding to the `this` pointer of the surrounding class efficiently in every context is not a simple proposition. The naive way to do it introduces a bug (`this` ends up pointing at the component passed the callback instead of the class) or creates unnecessary closure instantiation on every rendering frame.

1. https://babeljs.io/docs/en/babel-plugin-proposal-class-prope...


A demonstration of Hooks is live right now at ReactConf and looks very cool: https://www.youtube.com/watch?v=kz3nVya45uQ (go back about 1.5 hrs into the past to see the start of the demo).


Dan Abramov's talk starts 39 minutes into the livestream: https://www.youtube.com/watch?v=kz3nVya45uQ&t=39m

If you like live coding demos, he also gave a talk at JSConf Iceland where he showed off some future React features, such as asynchronous rendering: https://www.youtube.com/watch?v=nLF0n9SACd4


Unfortunately the video has been blocked due to copyright. My guess is they played music during downtime.


This document give me tinglings. Something about how the hooks just click with me and I can see how the web changes with WebAssembly and multiple compile targets (native, desktop, etc.), this will make our lives easier.


So adding class lifecycle events to functional components? Why not just use a class?

The beauty of the functional components is that immediately you know there's ZERO state in here. It's just rendering markup based on input.

Now there's more to look out for given this `hook` thing. I don't like it.


This is an excellent point, not sure why you've been voted down. So now functional components can't be guaranteed to maintain their best property? Weird.


I think this is a really positive solution to creating a streamlined functional api.

However, in its simplicity (and hidden magic), I fear that it won't encourage junior devs to understand what's actually going on, and thus may lead to bad code (eg monster components with lots of side-effects running on render).

In a way, this reminds me of MeteorJS, which was awesome for new devs getting up to speed with a powerful JS environment under the hood. However, by internalizing much of that power, it became too closed off, too difficult to build and compose new patterns around. And is now mostly irrelevant. Not saying that's React's future (I'm all-in on React and excited for this), just a concern / thought.


This is interesting. I'll have to spend some time mulling over this before the benefits sink in. It seems like a much more confusing and less composable API than recompose, which is how I add state, lifecycle, and other React class features to functional components. I've been completely avoiding React classes for a while now and using stateless components with recompose for over a year now, and I find it to be a wonderful architecture for component testability and reusability.

https://github.com/acdlite/recompose/blob/master/docs/API.md


The author of recompose just end of life'd it today in favor of Hooks. Read his comment on the top of the recompose readme.


Still, I'll be looking into the hooks pattern and determining how it will work for my projects and especially how easy it will be to port my large number of reusable HOCs from recompose to React hooks.


That author is Andrew Clark, who's also a React core team member and helped design and implement hooks in React :)


Recompose is not really compatible with TypeScript (no clue about Flow). Render props are a good alternative but the nesting made composing a bit cumbersome. Hooks are easy to type and compose quite fine it seems.


I don't know much about TypeScript, but is any React HOC function composition compatible with it? It seems like it would be difficult for TypeScript to typecheck a compose function where you can do compose(hoc1, hoc2, hoc3), where each HOC renders a child component with some props added.


You can write HoC with working typings [1]. As far as I know the compose function is harder to type because of the varargs it uses (although I heard recent TS versions can actually handle that).

[1]: https://medium.com/@jrwebdev/react-higher-order-component-pa...


Right but with recompose you get extra wrapping components in your tree which is what they were trying to avoid.


What 'tree' are you referring to? Higher order components are just functional components that accept a component as a argument and return a new component. There aren't any additional nodes added to your VDOM unless you specifically make a HOC that does that.


The component tree.


Then yeah you are incorrect. You are not adding any additional components to the tree. Higher order components are just a design pattern. How you implement that pattern will decide on the component tree, but there is no additional "wrapping" penalty for using them.


I absolutely fell in love with React when I switched over from Angular many years ago. Loved the simplicity of the API and how you had to be explicit about everything. Over the years, I've seen React start adding a lot of "optional" APIs which increase the surface area anyway. This made me explore other options and now that I've started doing some Elm, I feel it's so much easier to reason with.

I guess this is the natural progression of frameworks. What was once simple will get complex until the next thing comes around.


Well, okay. Preact exists. Even mithril.js isn't completely dead.

Sad, though. A framework can afford a lot of technical debt, but adding more conceptual debt, like React was doing recently, seems to me like a road to oblivion^W legacy status. Features that lack clarity and come bundled with footguns tax developer's brain resources, and increase the rate of errors. These are some of the most expensive resources in IT, and fighting errors lengthens time to market.


> Even mithril.js isn't completely dead.

That's a rather un-generous description of a framework under active development with an active community.


A lot of code is 1-2 years old.

Though I'm happy that mitrhil.js lives and is being developed (not just maintained). I only wish it wider adoption.

The "not completely dead" was meant to be somehow tongue-in-cheek.


v2.0 is coming. Breaking changes are minor stuff. Migration of my very large app took me about an hour. The API of mithril is pretty much settled, which IMO is a good thing. We even plan to remove stuff for next major. Simplicity is key.


This is marketed as a proposal and a RFC, but it's already in React v16.7.0-alpha.

If it turns out to be a bad idea (hypothetically speaking, I haven't read the article yet so I don't know), will it be backed out?

Wouldn't it make more sense for it to be versioned as an experimental fork/branch instead?


Yes, if we decide not to include this we will definitely back it out. However we’re excited and hoping that we can agree on something everyone will love.

We could use a separate branch but in practice we prefer to use feature flags for development; we find it easier to manage. Once we reach a definitive conclusion on whether to include it, we’ll remove the feature flag.


Oh great. Another React feature that relies on creating anonymous functions every time your component renders.

I presume this is now adequately fast in the various JITs in use, because I seem to remember this being one of the major bottlenecks React developers were instructed to avoid doing at all costs.


Yeah, they answer this in the FAQ too.

> In modern browsers, the raw performance of closures compared to classes doesn’t differ significantly except in extreme scenarios.

https://reactjs.org/docs/hooks-faq.html#are-hooks-slow-becau...


Nah, this has nothing to do with that. If you pass an anonymous fn to a pure-component its shouldComponentUpdate part flags it for re-rendering since the property is new every time, which can be a problem depending on how large its payload is.

Creating a function costs you a few clock ticks, there is no bottleneck, rendering a component and its entire sub tree for no reason on the other hand can be critical.


There’s a useCallback hook for this


I don't want useState to magically determine which state to use via call ordering. I want to pass a unique ID string to useState and have that determine which state I want.

Order-based management could then be opt-in, and based on a non-magical ID-based system.


I don't dig what they're doing, but I do kind of like the idea of a deconstructed getter/setter:

[ get, set ] = getterSetter(defaultValue)

as a wrapper around some stateful, immutable value (mutating the result of the get won't be tracked, that is)


That's pretty much what useState does. (or maybe you were already saying you liked that -- sorry, if that's what you meant) The only difference being that the "getter" has already been "executed" in a way: useState returns a value and a setter. Changing the value won't get tracked, and a call to the setter will overwrite the old value and re-render.


Yeah -- I'm saying it's dubious that there's magic here "doing the setState queue for you" -- notice the function call isn't bound and there's no passing of "this", so it's gotta' got some magic under the hood with some global context.

I do, however, like the concept for the react style of render -- being able to grab a getter/setter from that is awesome. They can remove the magic by simply doing:

const [getter, setter] = this.useState(...)


It's nothing more than React already knowing exactly _which_ component it's working on rendering. See my other comment here: https://news.ycombinator.com/item?id=18306957


No sir, I don't like it :/ I don't see a simple API, I see a completely magic black box that is going to chew up my fingers if I decide to put my hand in it.

Don't fight the language! JS is a still an evolving language, class properties are at Stage 3 draft, and have effectively been usable for years already. I feel the verbosity argument against classes is complete bunk.

When you write "TLDR: There are no plans to remove classes from React... Crucially, Hooks work side-by-side with existing code so you can adopt them gradually... Finally, there is no rush to migrate to Hooks." it doesn't give me the warm and fuzzies, quite the opposite. I can feel the momentum is going to shift to the new hotness and a completely different way of doing things and I'm not sure I want to go where you're heading. Until the next shiny thing.

I wish React would stop adding to the core library. I strongly feel most of the innovation should be happening in libraries surrounding it, even if they're first party libraries, with the core being much slower to change. A good reason to change the core would be taking advantage of new standardized JS features in the future, or (minimally breaking) changes to support big ideas like async rendering. Changing the fundamental way you write React code because "classes are confusing" is just a terrible reason!


Someone much smarter than me said something like "good magic decomposes into sane primitives". Jury's still out on whether Hooks and "useState" qualify.


I wish they'd work on global event based system to pass state, like redux but built in and steam line it for all use cases like promises. React state propagation sucks.. what Vue is doing with events is basically imitating redux but easier. Context API is very lacking and similar boilerplate as of redux


> Hooks allow you to reuse stateful logic without changing your component hierarchy.

Why haven't ES7 decorators been more widely adopted for this? We've been using them for over a year for this purpose now and they've ended up being far cleaner, more powerful, and more composable than the proposed interface.


Decorators haven't been adopted because they are not specced or shipped.

There is no decorator feature in the ES7 (ES2016) spec.

However, there is a proposal for decorators that it is not finalized yet.

https://github.com/tc39/proposal-decorators


On the positive side hooks provide a lot of options for declarative abstractions. I expect that to a large extent the built-in hooks will be used as building blocks for new libraries. I think it is likely that this will outweigh the negatives.

On the other hand, hooks rely on hidden side effects so that each hook invocation returns something different depending on which component instance in the component tree is being rendered when the hook is called, and the number of times the hook has already been called while rendering that instance. This introduces semantics that are unlike anything I know of in the language. A redditor, u/hardwaregeek, pointed out that hooks behave kinda like a state monad, albeit emulated with imperative side-effects.


I really wish React wouldn't add more state handling, because it's never been particularly good. I use MobX and loathe the overcomplication of stuff like e.g. Redux. Hooks look like a misguided attempt at addressing React's lack of automatic reactivity.


Nice. Its attending to the same *intention as https://github.com/acdlite/recompose but without as much boilerplate (and without HOC which carry some drawbacks)


I'm actually most comfortable with object-oriented programming since I started doing that 26 years ago. However, this simplifies the lifecycle business somewhat and results in a slightly cleaner JavaScript syntax than the class based way in my opinion.


Another clear signal that React alone isn't enough and should be used only as renderer.

Now get off my lawn while I tend to my rum*

*https://github.com/tonsky/rum


Very cool feature. It reminds me of MobX where changing the observable value auto queues a render. It’s super productive. With hooks calling the setter auto queues a render too.

I’ve had a few embarrassing bugs in the past where the page route changes but it’s the same component so it doesn’t call componentDidMount and doesn’t fetch the new data. It looks like hooks default to fetching data too often instead of not enough which feels correct. Instead of users wondering why the page is broken your team is wondering why the server is getting 1000x more requests.


This is pretty interesting but it's not immediately obvious whether it's an improvement over the current system.

Looks like one of those things you have to use for a couple of days before coming to a conclusion.


Front-end devs need to first master the vanilla tools, then reach for the frameworks once they understand the why.

I'd like to see a build tool that focuses on plain HTML, CSS, and ES6 modules. It takes the input .html file, parses the <script type="module"> elements, and statically analyzes the code to polyfill and re-write output for specified browser compatibility.

I think part of the problem is that the intro tutorials for the fully loaded frameworks look so much simpler at a glance than trying to wrangle something on your own.

Any ideas for youmightnotneedreact.com?


On the one hand I'm not sure if I like how this paradigm hides it's implementation so thoroughly - abstractions whose core is invisible to the developer is how simple libraries turn into monstrosities.

On the other hand, this will finally make functional component viable, and actually let us get mixin functionality.

I think it's a good idea, maybe even a great idea after a few adjustments, but it doesn't really belong in core IMO.


I like how it makes it possible to re-use behaviour among components, but I also really liked how classes encouraged structure and readability.

My hunch is it's only a matter of time before someone creates a helper that would enable `useState` to take complex objects rather than calling it multiple times.

Also, custom hooks seem almost too powerful - easy to build multiple abstraction layers and make the API feel magical at the point of use.


> My hunch is it's only a matter of time before someone creates a helper that would enable `useState` to take complex objects rather than calling it multiple times.

You can already do that, although it's not _exactly_ the same as setState in a class (states aren't merged together... but if you really wanted to, it'd be about five lines to implement a custom hook)

    const [state, setState] = useState({
      foo: "123",
      bar: "abc",
    });

    function updateBar(nextBar) {
      setState({ ...state, bar: nextBar });
    }


Cool idea, feels a bit like observables, especially the unsunscription via returned callback.

The call order thing seems odd. Don't know how to sell this to people.


Angular's problem with observables is being completely mismatched with component state. You have to unsubscribe stuff manually all the time with any complex app, and it's a nightmare to debug when you've forgotten. You can use `@ngrx/utils` with class-property attributes now, but it's still weird and not always applicable and like most angular things, couldn't be coded by a newbie as it relies on the vomit-worthy-but-kinda-works metadata system.

AFAICT, with state+event hooks you could just write a function in a few lines to subscribe to an observable you pass to it, setState on each new value, and unsubscribe, and then use it everywhere.

(Edit: yes, of course there is the | async pipe. Not everything is in the template though.)


I always had the feeling Cycle.js is the better observable framework.


After a go around only 3/31 people at our department agreed to adopt this.


Applications are open for YC Summer 2019

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

Search: