Hope you’ll enjoy reading it.
Hope you’ll enjoy reading it.
Thank you for the time and effort you're putting into this.
I understand that it implements some kind of inversion-of-control, but just looking at the code it feels like using some global object's method which is a big no-no. Also this importance of ordering reminds me the unmaintainable magic hell of Angular.
Maybe I'm just missing the "explicit-over-implicit" concept here. What's your opinion on this?
React has always been about taking useful ideas from functional programming and bringing it to mainstream through pragmatic choices in JS.
Your concern about the "globalness" is addressed in Sebastian's comment which is linked five times throughout the post — you should definitely check it out! https://github.com/reactjs/rfcs/pull/68#issuecomment-4393148...
Finally, don't forget you're comparing Hooks to classes. Those are hardly functional either.
The posters here wondering why you can't name them are on to something. I assume it's because then it'd be too obvious that's what they're doing, and whoever's paying people on that team (I really hope it's not more than one person, it's not hard work, but it probably is) might notice and make them stop, and maybe the React team at FB would even shrink in size, and we can't have that.
I'm not sure what other explanation there could be for such comically-wasteful sandcastle building. I assume it's a combination of individual incentives to work on something not-difficult but flashy and prominent, with project incentives to never need fewer people than they currently have.
Can’t name what? Not sure I follow.
>I really hope it's not more than one person, it's not hard work, but it probably is
We had from 5 to 8 people on the team at different times. Maybe maintaining one of the most popular open source projects isn’t “hard work” for you but we find it challenging.
>I'm not sure what other explanation there could be for such comically-wasteful sandcastle building.
We try to solve problems that product engineers run into. If you have better ideas we’d love to hear them.
Imprecise phrasing on my part, the discussion here has been around naming hooks with Symbols.
> We had from 5 to 8 people on the team at different times. Maybe maintaining one of the most popular open source projects isn’t “hard work” for you but we find it challenging.
I meant React Hooks specifically, not Redux, which I assume is what you mean here.
> We try to solve problems that product engineers run into. If you have better ideas we’d love to hear them.
Use the built-in OOP system instead of writing a worse new one? Reinventing methods and properties with poor, misleading syntax as a thin layer over the OOP system of the host language is... well, it's helping bloggers, I guess.
We’re very open to good technical arguments but this isn’t one.
Maybe? I usually very much would not, of course, but JS "culture" creates significant irritation and wasted time for me daily, and has for years, especially in React-land, since that's where the money is lately so it's hard to avoid. The only other software that gets me this exasperated is anything Poettering thinks up, but at least I don't personally have to work closely with any of that daily (any more, and for now).
I'm sure I'll have to deal with hooks when people around me start using them. It's less that I'm upset that they exist than I feel like I'm being gaslighted. I've read the docs, and the source, because, again, I have to know this stuff. After the initial disbelief wore off I had a good laugh, like, actual LOL. This thread is the first of many I at that moment predicted I'd see as people who really, really in their hearts and in their actual technical needs and in the language they're using, just needed OOP, but are on the JS-must-be-functional-at-all-costs hype train, expressing frustration and confusion over this feature and burning lots of time trying to sort out how OOP works when you're trying so hard to not type "this" and pretending it's something else. It's a less-useful and confusing replacement for OO that re-implements just enough of it that people will 100% for sure hang themselves with it, and omits enough that people will complain about it. It's a perfect device for generating confusion. It's going to be used for no benefit, or misused harmfully, a ton, and meanwhile everyone's gonna be very confused about it.
Ditto Redux—which is at least not funny in itself the way React Hooks are, though the flailing and consternation around it are—which is dead simple if you don't use the wrong words to describe things, yet how many person-hours have been lost trying to decipher what's going on there? So, so many. On the one hand it's funny, and I do legitimately enjoy all the accidental humor in React land. On the other I have to console, counsel, and train the folks who run into difficulty with this stuff, and live with or fix software in which it's been misunderstood and misused.
I’d love to see what OOP solution you envision for these problems. It’s not like we’re unfamiliar with OOP. In fact the OOP version of Hooks is what we had before. It’s called mixins. Mixins, like other forms of multiple inheritance, suffer from the “diamond problem” described in the post, and many others:
https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamo...
https://reactjs.org/blog/2016/07/13/mixins-considered-harmfu...
If you have an OOP solution that solves the same problems Hooks solve, but without the downsides of mixins, I’d love to hear it. You’re being vague in your proposed fix which makes it difficult to discuss.
I also want to emphasize we’re not “FP purists”. (In my opinion some codebases take FP way too far making the code very difficult to follow.) In many ways, Hooks help replace those heavy-handed patterns. So I think you might actually like them if you spend some time using them.
Thing is, I don't even consider Hooks not OO. They're just a really limited in-JS partial re-implementation with bizarre syntax. React tracks your "this" for you so it can dispatch the calls correctly. Your constructor gets mushed around in your render function for some reason. But it's attaching properties and methods to an instance. It's going to require care and discipline to use it correctly, given its quirks, so just direct that same discipline toward composition-over-inheritance instead, is my thought, which you can do without yet another way to write things. The fix is quit hitting yourself, in short, but if you don't I guess we'll hand you another way to hit yourself, but differently? This is just one more layer of complication that everyone's now got to understand (or, more likely, not, but use anyway) to even read other people's React codebases.
There’s neither methods nor properties in Hooks code. I think you might be doing the same thing you think we are doing — you’re projecting the API you see onto the metaphors that feel more familiar to you. But these metaphors don’t really match what the API is doing or what it represents.
But again, this discussion is fruitless without specific code examples to anchor it.
I mean that Hooks implementation re-implements key elements of a typical implementation of methods and properties, and end up mimicking them in important ways, differing mainly in the parts of that it doesn't include. Not that it actually uses methods and properties (though it does, of course—the "current component" that React tracks is an object, and the Hooks code leans on that to determine its calling context).
> you’re projecting the API you see onto the metaphors that feel more familiar to you.
Place a typical OO implementation next to what Hooks are doing, and you don't even have to squint to see that they're quite close. The porcelain's super-weird, yes—magical in all the "wrong" places, explicit in all the "wrong" places, missing a ton of mostly-inheritance-related stuff—but even with all that a Render function using Hooks manages to look an awful lot like a class declaration, as if someone had implemented classes in a language but forgotten to add any of the syntax to support it.
EDIT: I mean, seriously. The source is public. It's a really fun read.
https://github.com/facebook/react/blob/master/packages/react...
That said, the presentation of the third and forth flaws seem a bit weak. useState accepts a key as the first parameter, but in both of the composite functions that input parameter disappears. That looks like a refactoring error.
From a design standpoint, if `useState(symbol)` is acceptable (and I'm not saying it is), then `useWindowWith(symbol)` would likewise be acceptable in that it's not adding any more requirements to the interface than the vanilla version.
Proper bookkeeping of symbols resolves the issues here. However, if the design objective is to reduce the effort on the developer to do their own bookkeeping, then call-order indexing does make sense.
(Not to mention that Symbols are not supported by IE11 which remains an important target for bigger companies.)
I'm not sure there's a good way out. When you look at solutions like Protocol Buffers, they just bite the bullet and require the developer to supply the indexing. If JavaScript had something like Go's iota, then you could imagine using an enumeration to supply the indexing without requiring everyone to type 1,2,3,4... etc. But it doesn't so, that's wishful thinking. Nevertheless, the react codebase itself does contain a giant list of assignments of Symbol() || number to constants, so it's a pattern you're already aware of.
A tough nut to crack.
I think you're missing that `useWindowWidth()` could have more than one `useState()` and thus you'd need to somehow compose Symbols. Which is what the next section is about.
https://gist.github.com/politician/5f03c169a4119a63abb785b1c...
EDIT: I still think it's a hard design problem and the concerns in flaw #8 are _very real_ to a broad range of developers. When you're just trying to get it done, proper bookkeeping of Symbols and injecting them into hooks composed of other hooks might cross the line. It's a shame that relying on call-order indexing is the solution because it's magical. But at the end of the day, engineering is about trade-offs. Time will tell whether deeply nested composition of automatically-managed hooks was a good feature to expose.
I've been thinking about this a lot since Hooks were introduced, and I'm increasingly of the opinion that it isn't that magical. Order of operations is incredibly important in the functions we write, especially in a language like JS that makes no effort for strict "pure" side-effect free functions. The order of a console.log or a return versus an increment matters in JS. We write a lot of procedural code in JS where order matters (a lot) already.
In that matter, Hooks can just melt into the "procedural" background of JS.
That said, I still feel like I want a better solution than "lint errors" for things like accidental branches of a Hook. I don't have any more of a proposal for how that would work or what that would mean than the article here, though, unfortunately.
The best I can come up with is Sweet.js (hygenic macros), but can you imagine what outrage that would provoke?
I keep trying to figure out if there is a way to push it into a type safety problem in Typescript, at least. A compile error would be preferable to a lint error, even if not everyone uses a typing compiler like Typescript.
If there were some way that you could get use* functions to narrow to `never` in any branch or branch-like position, that would be cool. Unfortunately, I can't think of a natural way in the type system to do that that would work in even a plurality of cases. Which drops back to it needing to be a context-sensitive linter rule.
Basically, lint, but at transpile time.
React.memo() is all the more useful of a signal in the Hooks world.