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.)
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!
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.
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.
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).
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.
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.
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.
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.
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.
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).
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.
Care to write a substantial contributing comment, or do you intend to keep this random complaint about the simplification of a common pattern in React as shallow as possible?
Edit: No really, I'd like to hear why you think this would make React a "clusterfuck mess" rather than... simpler.
I feel like Redux was a clusterfuck mess and this is the cleanup. Excuse the language.
Edit:
Expanding on this and why (I think) this solution is cleaner:
* In redux you ended up with pointless constant piles of strings that are the named actions. Totally useless in a JS world where a function that IS an action can take up that mantle.
* While reducers are a good way to make state consistent, using redux for state management when you actually don't have 17 different producers and 1 consumer it's major overkill. Most of the time you actually have 1 or 2 event (and value changing) producers and MANY consumers on the screen at one time.
* When you DO need a reducer, instead of making that the norm, this new hook library does provide a useReducer function that works exactly like that- and guess what? NO STRING CONSTANTS YAY.
I think the only downside I can think of is TTDebugging might be complicated to create under this dome, but was the same issue for stateful classes. That being said, it might be more possible now that the control is placed in a single feature area.
I'll point out that Ryan's demo _did_ show using string constants with `useReducer()`.
Also, our new `redux-starter-kit` library auto-generates action types and action creators for you, _and_ modifies the action creators so they can be used for the `case someAction` comparisons: https://github.com/reduxjs/redux-starter-kit .
Redux is based on the Flux Architecture. In particular, it carries on the idea of describing events or state update requests as plain objects. One of the key insights of Redux is that you can then write additional logic to act on those actions as they progress through a centralized pipeline (ie, middleware).
I've seen lots of Redux-alikes that are "Redux, but without reducers/actions/etc". They mostly claim that they're making things simpler, and in some ways, maybe they do. But, what they're also doing is throwing away the ability to act on those actions as they get dispatched. If I "dispatch a function", I can't programmatically inspect its contents, modify it, log it, attach additional info to it, or all the other myriad of useful things you can do with a plain object.
As for the type strings, you need some kind of useful identifier to distinguish different action objects. You could use Symbols, but those don't serialize well. You could use numbers, but those aren't very meaningful when viewed in an action history log. Ultimately, you want your app's reducer logic, middleware, and the action history itself to be readable and semantically meaningful.
I think then perhaps redux may simply not be for me. I do feel like unfortunately a lot of teams use it anyway, giving React and a few other things a complex feel. When you suddenly take it out of React, at least for simple use-cases, you suddenly feel like React is incredibly simple.
If more teams had been more selective about Redux or to simply use it JUST for global state things like color themes, logged in user, and probably a half dozen other things it might have fewer people burned on it.
I'm definitely not in your shoes - you're a redux maintainer and I do apologize for my "clusterfuck" comment. But I think fewer people would be burned if architects at the top didn't mis-use and abuse. I've been in projects where just about every tiny little input, checkbox, on 30 or so forms had to go through a convoluted redux action. Then when I finally got into my own React usage, without redux, it was like a super-genius baby landed in my lap dancing like it was 1999.
People use Redux way too often and think of features like time travel as nice-to-haves, when in reality they're the main reason why you'd want to use Redux in the first place.
Using Redux just to simply set and get data on every page is an overkill.
For the majority of applications making API calls directly from the component and storing data in the comp state is the way to go.
This is coming from someone who used redux excessively in the past.
What do you do when you want to update state in other places in response to a change in a component? How about if you want to make your component's state persistent (particularly when the component is external to your project)? Also, what do you do to generate state dumps for error reporting?
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).
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
It's a huge difference, and yet also the same thing.
It's the same concepts of props, state, context, and lifecycle behavior as before.
It's just that now you can do it in function components, not just class components, and the APIs let you handle things without having to have additional levels of wrapper components and without the complexity of class-related gotchas.
Can someone give me an example where hooks replace a wrapper? All the examples I see can be replaced with a single class, albeit a couple more lines of code.
Context is a great example. Right now, each `<MyContext.Consumer>` instance shows up as another level of wrapping in the devtools, _and_ requires indentation/hierarchy in the render methods. With `const someValue = useContext(MyContext)`, there's no actual component being used, so both the component hierarchy and the render code itself is flatter.
"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)?
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.
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.
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.
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.
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:
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:
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.
> 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.
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.
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.
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.
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.
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.
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)
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.
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
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
> 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 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.
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).
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).
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.
> 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?
> 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.
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.
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.
> 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.
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.
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.
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!
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.
> 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.
(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.
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.
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.
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.
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.
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.
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.
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).
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.
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 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 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.
> React doesn’t offer a way to “attach” reusable behavior to a component
I know the angular resentment here is high, but some things Angular 1 got right. Directives added as attributes to another component was very powerful and allowed this in better ways than HOCs in React. Im looking forward to try this out.
I think the Angular resentment is a little behind the times, the days of Angularjs 1 and the beta versions of Angular 2 are behind us. The new Angular is worth a look, especially if react is now having various extras bolted on ad hoc.
> the days of Angularjs 1 and the beta versions of Angular 2 are behind us
There is still a _heap_ of Angular 1 code out there since the 1 -> 2 move basically meant you couldn't upgrade without a full rewrite. Both my last two jobs have involved re-writing Angular 1 apps.
Sure, there are lots of Angular 1 apps still in production, as there will be with most legacy systems. My point is that Angular 1 is no longer the current version, and with the latest version it’s much better to use. I think the main issue is the learning curve, but you just have to bite the bullet.
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’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 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.
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.
281 comments
[ 3.3 ms ] story [ 162 ms ] threadThe call order thing seems odd. Don't know how to sell this to people.
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.)
> 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!
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.
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?
(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.)
Simple example case of a statement that makes it impossible to minify function names:
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.
No, but it could be designed around the fact that some of the language features are confusing or crap.
[0]: https://github.com/acdlite/recompose
https://github.com/acdlite/recompose/blob/master/docs/API.md
[1]: https://medium.com/@jrwebdev/react-higher-order-component-pa...
Edit: No really, I'd like to hear why you think this would make React a "clusterfuck mess" rather than... simpler.
https://github.com/facebook/react/pulls?q=is%3Apr+is%3Aclose...
Even the developers have no idea WTF is going on.
Edit:
Expanding on this and why (I think) this solution is cleaner:
* In redux you ended up with pointless constant piles of strings that are the named actions. Totally useless in a JS world where a function that IS an action can take up that mantle.
* While reducers are a good way to make state consistent, using redux for state management when you actually don't have 17 different producers and 1 consumer it's major overkill. Most of the time you actually have 1 or 2 event (and value changing) producers and MANY consumers on the screen at one time.
* When you DO need a reducer, instead of making that the norm, this new hook library does provide a useReducer function that works exactly like that- and guess what? NO STRING CONSTANTS YAY.
I think the only downside I can think of is TTDebugging might be complicated to create under this dome, but was the same issue for stateful classes. That being said, it might be more possible now that the control is placed in a single feature area.
Also, our new `redux-starter-kit` library auto-generates action types and action creators for you, _and_ modifies the action creators so they can be used for the `case someAction` comparisons: https://github.com/reduxjs/redux-starter-kit .
https://reactjs.org/docs/hooks-reference.html#usereducer
To something without strings and hard-coding the actual "reduction code" to something like
export const increment = (state) => ({count: state.count + 1});
And give modern JS languages like typescript import the increment function and use it directly?
Why are we so attached to these action type strings?
I've seen lots of Redux-alikes that are "Redux, but without reducers/actions/etc". They mostly claim that they're making things simpler, and in some ways, maybe they do. But, what they're also doing is throwing away the ability to act on those actions as they get dispatched. If I "dispatch a function", I can't programmatically inspect its contents, modify it, log it, attach additional info to it, or all the other myriad of useful things you can do with a plain object.
As for the type strings, you need some kind of useful identifier to distinguish different action objects. You could use Symbols, but those don't serialize well. You could use numbers, but those aren't very meaningful when viewed in an action history log. Ultimately, you want your app's reducer logic, middleware, and the action history itself to be readable and semantically meaningful.
If more teams had been more selective about Redux or to simply use it JUST for global state things like color themes, logged in user, and probably a half dozen other things it might have fewer people burned on it.
I'm definitely not in your shoes - you're a redux maintainer and I do apologize for my "clusterfuck" comment. But I think fewer people would be burned if architects at the top didn't mis-use and abuse. I've been in projects where just about every tiny little input, checkbox, on 30 or so forms had to go through a convoluted redux action. Then when I finally got into my own React usage, without redux, it was like a super-genius baby landed in my lap dancing like it was 1999.
Using Redux just to simply set and get data on every page is an overkill.
For the majority of applications making API calls directly from the component and storing data in the comp state is the way to go.
This is coming from someone who used redux excessively in the past.
In 90% of the cases one of the parent components. Sometimes redux when the component tree goes super deep, or for things such as currentUser.
> How about if you want to make your component's state persistent (particularly when the component is external to your project)
What do you mean? Give me an example.
> Also, what do you do to generate state dumps for error reporting?
I don't generate state dumps for error reporting.
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
It's the same concepts of props, state, context, and lifecycle behavior as before.
It's just that now you can do it in function components, not just class components, and the APIs let you handle things without having to have additional levels of wrapper components and without the complexity of class-related gotchas.
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)?
Note they also say:
> We provide a linter plugin to enforce these rules automatically.
Makes me feel a little better.
Like, if I have two state variables, pass in a name for both, instead of relying on the order being the same.
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.
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.
With `useEffect`, I have no idea what is actually happening here, and I've tried re-reading it a few times.
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:
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.
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:
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?
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.
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.
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.
"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.
https://www.youtube.com/watch?v=kz3nVya45uQ&t=39m (from elsewhere in the comments here)
LOL, did they just block a video presentation for some incidental random music in the background?
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.
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.
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.
Sure, I know what it does and why it is needed, but it is ugly, cumbersome, and I keep forgetting it nonetheless.
- https://www.npmjs.com/package/babel-plugin-autobind-class-me...
- https://www.npmjs.com/package/babel-plugin-transform-class-p...
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.
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
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 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.
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.
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.
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.
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.
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.
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.
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).
How is static typing "mental laziness"?
``` 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).
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.
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.
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.
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.
This. This is spot-on IMHO.
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.
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.
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.
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.
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.
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.
Looks like one of those things you have to use for a couple of days before coming to a conclusion.
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.
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 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...
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.
https://reactjs.org/docs/hooks-faq.html#how-to-test-componen...
What exactly looks difficult about testing them? Existing components already carry state and use lifecycle methods...
If the goal is helping developers "fall in to the pit of success" I think classes are a much better option than this.
LONG LIVE class based component, there was nothing wrong with them. Don't fix it if ain't broke.
Is that progress? I'm too old to think so.
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.
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?
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.
This is going to make it about a million times easier to use Typescript with React.
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.
I know the angular resentment here is high, but some things Angular 1 got right. Directives added as attributes to another component was very powerful and allowed this in better ways than HOCs in React. Im looking forward to try this out.
There is still a _heap_ of Angular 1 code out there since the 1 -> 2 move basically meant you couldn't upgrade without a full rewrite. Both my last two jobs have involved re-writing Angular 1 apps.
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.
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.
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...