
Why Do React Hooks Rely on Call Order? - stablemap
https://overreacted.io/why-do-hooks-rely-on-call-order/
======
fogetti
Beg to differ, yes, implicit call order will result in huge clusterfucks.
React+Redux is already causing Frankenstein apps (which is not implicitly
caused by those frameworks (ok, maybe except redux) but when you throw in
react-redux, react-router, redux-thunk, etc. in the mix it just deteriorates
quickly).

Well the NPM report showed us the trends. Every major fad peaks around 5 years
in the making in JS land and then it fades away. We are halfway through. We
just have to sit through the next 3-5 years.

~~~
davnicwil
You can write really messy confusing apps with lots of magic and indirection
with anything, redux included, but redux by design enforces a single, mono
directional and easily traceable chain of events whenever you fire an action.
Whether you have 1 action or 100, this doesn't change. It's not, in my view, a
pattern which works in the simple case but doesn't scale up.

Actually the complexity of understanding redux actions and their effects
doesn't seem to change much at all from small to very large apps. This may
come down to a well designed state tree (data model), or designing simple
actions that don't try to do too much. There are actually big parallels with
API design. It might even be the same problem.

So does a badly designed REST API mean REST as a concept is the cause? Of
course not. In most cases, REST isn't even a limiting factor. It's just been
badly designed and badly implemented. I think it's the same with blaming redux
for a poorly designed, poorly implemented web app.

~~~
cageface
In actual use I've seen that Redux apps often wind up with a lot of accidental
data dependencies that probably wouldn't have happened without a centralized
store. For example devs will lazily use a "currentUser" key in the store for
all kinds of unrelated stuff and subtle bugs creep in. Another common problem
with Redux is memory issues because various components don't clear their data
out of the store when they're unmounted.

Redux has some nice features but at this point I recommend people avoid it
until they start to suffer from some of the problems it was designed to solve.
You can get pretty far with a lot less complexity by use using local component
state in vanilla React.

~~~
davnicwil
I absolutely agree with you and that's been my experience too, I've seen
exactly those problems in both my own code and others' code. It took me
personally many iterations over various projects to learn the boundaries of
where redux makes more sense and where component state makes more sense.

That's perhaps the biggest actual inherent problem with redux, that it _may_
implicitly encourage everything to be in the one single centralised store, for
newcomers. That's a hard problem to solve, though I'm fairly certain Dan
Abramov and the other maintainers have tried to make it clear that this, and
using redux at all in simple apps, is usually a mistake.

~~~
acemarke
Hi, I'm a Redux maintainer.

The Redux FAQ specifically has an entry with rules of thumb to help decide
when it makes sense to keep a given piece of state in Redux [0].

I do agree that the "Single Source of Truth" principle [1] is probably over-
interpreted, and maybe needs some caveats somehow. That said, it's tough to
simultaneously say "here's the basics of how Redux works", "here's the ideas
behind why you _should_ use Redux", and also try to tell people when to _not_
use Redux.

We're currently planning a revamp of the Redux docs content [2]. I'd
appreciate it if you could fill out this survey on how we can improve the docs
structure [3], or leave a comment in that issue thread with some suggestions.

[0] [https://redux.js.org/faq/organizing-state#do-i-have-to-
put-a...](https://redux.js.org/faq/organizing-state#do-i-have-to-put-all-my-
state-into-redux-should-i-ever-use-react-s-setstate)

[1] [https://redux.js.org/introduction/three-
principles](https://redux.js.org/introduction/three-principles)

[2]
[https://github.com/reduxjs/redux/issues/2590](https://github.com/reduxjs/redux/issues/2590)

[3]
[https://docs.google.com/forms/d/e/1FAIpQLSfzIkY3fXZ8PrQKScYM...](https://docs.google.com/forms/d/e/1FAIpQLSfzIkY3fXZ8PrQKScYMK0YoEgALfAK2qQ0mOj1_ibKv2qDTuQ/viewform)

------
thomasfoster96
I think this post has actually pushed me back towards Symbol keys perhaps
being a good idea. The useFormInput() example under Flaw 3 seems rather
contrived – wouldn’t you just pass a Symbol key to useFormInput and it would
then pass the key to useState, solving the supposed flaw? If you had to use
useState several times in useFormInput, just use a WeakMap (they’re not _that_
scary) with the keys being the Symbols passed to useFormInput. Or am I missing
something in the explanation?

~~~
genezeta
It's not really well explained in the article, but the argument against
Symbols is that you (client code) have to store them somewhere for reuse in
different calls.

That is that, you could do...

    
    
        useState("someID")
    

...and somewhere else (* or in the same place but on a different call)
again...

    
    
        useState("someID")
    

...and this indeed refers to the same item. But using a Symbol, you need to
first create it, store it somewhere and then use it. That is, you _can 't_ do
this...

    
    
        useState(Symbol("someID"))
    

...because this _will_ fail through different repeated calls. Instead you'd
need to first...

    
    
        let someSymbol = Symbol("someID");
    

...and then...

    
    
        useState(someSymbol)
    

Or, alternatively, use Symbol.for("someID"), which then has both problems:
creating the symbol first and clashing of identifiers.

While the article does not explain this clearly, the example used alludes to
this in an indirect way.

Personally I do think that this would be a more desirable sacrifice to make
than restricting call order, but the React team thinks otherwise, it seems.

~~~
thomasfoster96
That’s not really all that different to everyone moving their CSS-in-JS and
GraphQL queries out of a functional component body though, is it? This is kind
of exactly the scenario Symbols seem to have been intended for.

Also... a nitpick, but `new Symbol` always throws a TypeError. And
Symbol.for() is a useful escape hatch.

~~~
danabramov
_> That’s not really all that different to everyone moving their CSS-in-JS and
GraphQL queries out of a functional component body though, is it?_

I suggest you to take the `useSubscription` example from the "diamond problem"
section and try to convert it to your proposed API. I think you'll see why it
falls apart.

(Don't forget effects would also need keys.)

------
city41
I’m surprised Reagent’s ratoms weren’t an inspiration. They give you a lot of
Hooks functionality largely through Clojure’s native atom.

~~~
lilactown
Yep. We've been using what is akin to an apollo-client hook at work for the
past ~9 months or so:

    
    
        (defn my-component []
          (let [user-data (data/pull! :user "{ user { firstName  } }")]
            (fn []
              (if (:loading @user-data)
                [:div "Loading..."]
                [:div "Hello, "
                 (get-in @user-data [:data :user firstName]) "!"])))
    

I'm a bit surprised this pattern isn't more popular; having side-effectful
functions return ratoms in a form-2 component seems almost as flexible as
Hooks. It seems that most CLJS people try and keep their views more pure,
which I think is honestly to their overall detriment. You miss out on the
encapsulation and composition that React is espousing.

That being said, I intend to replace reagent soon with just raw React + a few
helpers :P

~~~
lauritzsh
> That being said, I intend to replace reagent soon with just raw React + a
> few helpers

Do you intend to keep using ClojureScript or use JavaScript/TypeScript? I read
pure React with ClojureScript is rather painful (mostly due to the props
conversion but maybe that's what your helpers are for?)

I am asking since I am still considering between React (JS/TS) and Reagent/Rum
(CLJS) for a side project of mine.

------
nihakue
Re: 'Flaw #6: We Still Need a Linter' (first example):

Could the 'primitive' hooks (useState, useEffect, etc) walk up
`arguments.callee.caller.arguments.callee.caller...` grabbing function names
until you hit a React function? Then use the names to create a 'composed' key
automatically? It still doesn't solve the problem of a function using the same
hook twice in one function, but it might solve the problem of collision across
custom hooks.

Example:

    
    
        function useCount() {
          const [count, setState] = useState(0)
          return { count, increment: () => setState(count + 1)};
        }
    
        function useCountPlusOne() {
          const {count: baseCount, increment} = useCount()
          return {count: baseCount + 1, increment}
        }
    
        function MyHookComponent() {
          const { count, increment } = useCountPlusOne()
          return ...
        }
    
    

Would give you a key of `useState(useCount(useCountPlusOne(MyHookComponent)))`
without the end user having to futz around composing the key manually. At this
point you could probably even forego the 'use*' convention

It's still pretty magical, but the magic seems more abstracted. In general
I've really liked hooks, and I'm willing to put up with the wackiness
(although testing them with enzyme is a big PITA right now).

Thanks for the article :)

~~~
WorldMaker
There are some big performance implications of using `arguments` (most current
JITs heavily deoptimize functions that use `arguments`), and arrow functions
in the spec are supposed to throw errors for any attempts to access their
`arguments`.

It's probably not a good idea for Production code.

------
benmmurphy
relying on call order does seem kind of scary but without knowing how people
structure their code using hooks its hard to know how bad it would be. for
example the situation with hooks is basically:

1) any function that calls a hook function has a red colour

2) any function that calls a red coloured function has a red colour

3) if you ever have ever call a red coloured function in a conditional branch
then bad things are going to happen

if you have nested functions calling hooks then you can change the order of
hooks without even realising hooks are being called which is dangerous. this
'nesting transparency' where callers aren't forced to know about the hook
behaviour of their sub-functions is also used as defence in the blog for
relying on call order. heh

~~~
danabramov
The "color" you're talking about is the "use" naming convention that's
enforced by the linter. So if you call a Hook, you're supposed to call your
function `useSomething()`, and we consider it a Hook too.

In practice we haven't seen this to cause confusion from people who actually
tried this proposal for more than a few hours.

See [https://reactjs.org/docs/hooks-
rules.html](https://reactjs.org/docs/hooks-rules.html)

------
Tade0
My gut feeling tells me that introducing hooks is going to end badly.

If there's no patently obvious advantage but you have to rely either on
convention or an additional pool of knowledge then most junior (or generally
less skilled) developers cannot be trusted to use the given thing properly.

I've seen this happen with observables - sure you can do a lot of new stuff
with them but they are only clearly more useful than say promises in a handful
of cases.

Thid trend of producing tools which are powerful in the hands of the best but
hard to use for beginners worries me. In the long run this makes development
more expensive, not less.

------
drabinowitz
I wonder if it would makes sense to enforce hooks being called through a top
level React function. To make some of the ordering more explicit

    
    
      function MyReactComponent() {
        const [
          [width, setWidth],
          [name, setName],
        ] = React.use(
          [useWidth],
          [useName, 'alice'],
        );
        return <div>{width} {name}</div>
      }
    

admittedly, this is much less clean looking than the current proposal, but, in
my mind at least, it makes it a bit more clear that you have to pass the
functions in with a specific order at the top of the component.

~~~
danabramov
I don't understand what exactly you're trying to solve by this (nothing
prevents a user from making it conditional) but it definitely has flaw #7
(can't pass values between Hooks).

~~~
drabinowitz
Ah that's fair about flaw #7

------
sfvisser
Sticking to attributes on classes doesn't have this ordering issue, because
construction only happens once.

    
    
        class Form extends ReactishComponent {
            name = this.useState('Mary')
            surname = this.useState('Poppins');
            width = this.useState(window.innerWidth);
        
            constructor () {
                this.useEffect(() => {
                    const handleResize = () => this.width.set(window.innerWidth);
                    window.addEventListener('resize', handleResize);
                    return () => window.removeEventListener('resize', handleResize);
                })
            }
          
            handleNameChange = e => this.name.set(e.target.value)
            handleSurnameChange = e => this.surname.set(e.target.value)
          
            render () {
                return (
                  <>
                    <input value={this.name.get()} onChange={this.handleNameChange} />
                    <input value={this.surname.get()} onChange={this.handleSurnameChange} />
                    <p>Hello, {this.name.get()} {this.surname.get()}</p>
                    <p>Window width: {this.width.get()}</p>
                  </>
                )
            }
        }

~~~
danabramov
How do custom Hooks look in this world?

~~~
sfvisser
Maybe something like this?

[https://gist.github.com/sebastiaanvisser/72e6bc54baa14abc08e...](https://gist.github.com/sebastiaanvisser/72e6bc54baa14abc08ec14196ea26623)

It all seems to boil down to packing and silently composing lifecycle methods.
Either with classes, records of functions, or effectful functions,
dictionaries.

I can see how the ergonomics of current react hooks are actually great, but I
still think they’re weird :) I’ll probably get over it some day.

edit: note how hooks are now parametrized datatypes, probably allowing you to
do all kinds of first class composition. Read only hooks are probably a
functor and a monad...

~~~
danabramov
How would you pass values between two different Hooks? See my two examples in
the post (useSpring and useFriendStatus).

Note they need to be always up-to-date and not just execute once.

~~~
sfvisser
With passing values between hooks do you mean "Make one hook depend on the
value of another hook?". Because that seems like the functor 'map', or
applicative 'apply'.

Note, I don't really know what these springs are, but derived hooks could work
like this:

    
    
        class MyComp extends ReactishComponent {
          fast = this.use(new Spring({ pos: [0, 0], config: "fast" })) // prim hook
          slow = this.use(this.fast.map(spring => ({ pos: spring.pos, config: "slow" }))) // functor map
          mid = this.use(combineTwoHooks((fast, slow) => computeMiddle(fast, slow), this.fast, this.slow)) // applicative
        
          render() {
            return (
              <>
                <Point pos={this.fast.get().pos} />
                <Point pos={this.slow.get().pos} />
                <Point pos={this.mid.get().pos} />
              </>
            )
          }
        }
    

The trick is functions that convert hooks into new hooks.

------
yiransheng
Hooks reminds me of tensorflow scopes a little bit, in python:

    
    
        with tf.variable_scope("foo"):
            with tf.variable_scope("bar"):
                v = tf.get_variable("v", [1])
                assert v.name == "foo/bar/v:0"
    
    

`v` tensor here will have a generated human readable unique name here:
"foo/bar/v:0"

It seems with hooks, react uses call order to derive the unique "leaf" hook id
for runtime resolving its implementations. However, it would be nice if react
hooks can automatically provide a similar human readable "hook id" (even if
only for dev/debug build).

    
    
        function useWindowWidth() {
          const [[width, setWidth], stateId] = debug(useState);
    
          assert(stateId === "useWindowWidth/state/:0");
    
          useEffect(() => { ... });
          const [_, effId] = debug(useEffect, () => { ... });
    
          assert(effId === 'useWindowWidth/effect/:1");
    
          return width;
        }
    

This will definitely help for nested custom hooks..

~~~
danabramov
For debugging, we will show Hook tree in DevTools by capturing and parsing
stack traces.

[https://github.com/facebook/react/pull/14085](https://github.com/facebook/react/pull/14085)

~~~
Klathmon
Could something like this be used to move the "linting" that the react team
recommends directly into react itself?

If you can abuse error stack traces to get the call stack, and some trickery
to get the string representation of the component function that called the
hook (following it through all intermediate custom hooks), you could then have
the full text of the function body and know for sure that it's calling a Hook,
and from there could run some linting on that internally and scream to the
console if a hook is being used incorrectly.

It may have a pretty significant performance and possibly size overhead
depending on how much code is needed to inspect the function body and actually
do the parsing/linting, but removing the need for a linter ("need" might be
too strong of a word?) would make it easier to get started with, and safer to
use for developers who, like it or not, don't read docs fully, don't setup or
use linters, or just want to throw something together with very little
tooling. And obviously it would all be stripped from production builds.

Has the react team explored this idea? and are there reasons that I'm missing
that it won't work or isn't ideal?

~~~
danabramov
Sebastian’s comment (which I linked to throughout the post quite a few times)
mentions we will probably do some DEV time validation with similar techniques.
I really suggest to read it all — my post wasn’t intended to answer _all_
questions.

[https://github.com/reactjs/rfcs/pull/68#issuecomment-4393148...](https://github.com/reactjs/rfcs/pull/68#issuecomment-439314884)

~~~
Klathmon
My apologies! I was on mobile when I read it last night and the RFC links
don't seem to go directly to the comment on my android device for some reason!
(it loads the full list of comments, but never takes me to the correct one,
and searching for sebastian didn't show any results, i guess because his
username is the only thing that shows up)

Thanks!

~~~
danabramov
Oh GitHub mobile can be pretty annoying. Glad you found it!

------
k__
Isn't the ID problem just a question of the type of the ID?

Sure strings would have collisions, but symbols wouldn't.

~~~
danabramov
You can search the article for "symbol" — there's a whole section dedicated to
that. :-)

~~~
k__
lol, that's what I did, somehow I didn't get any results.

Maybe a typo, thanks for the heads up :)

------
maaaats
> _Flaw 2: One common suggestion is to let useState() accept a key argument
> (e.g. a string) that uniquely identifies a particular state variable within
> a component._

I tried asking about that earlier here on HN[0], nice to finally at least get
an explanation. The tldr is name clashes when reusing hooks. A valid concern,
I think they should be more upfront about the reasoning instead of "hooks are
magic, don't use them in these ways". That would make it easier to accept.

[0]:
[https://news.ycombinator.com/item?id=18640612](https://news.ycombinator.com/item?id=18640612)
(and the blogpost in the answer didn't really answer it)

~~~
k__
Wouldn't symbols solve this issue?

~~~
genezeta
Yes, and to some extent it is addressed in the link too (though not really
well explained).

Symbols do not clash, but they need to be managed/stored by client code. i.e.
you need to keep the original Symbol to use it in different calls, while you
can use "different equal strings".

This is the argument in the article. Whether this is indeed more or less
desirable than having order restrictions on calls, that's a different thing. I
personally think it is indeed a better solution, but the React team seems to
think it's not.

~~~
danabramov
Symbols _don 't_ solve this without extra closure wrapper and Hook
"instantiation" (described in flaw #5).

Passing a Symbol to custom Hook from outside also doesn't work because a
custom Hook may have more than one state.

Try to convert the `useSubscription` example to your proposed API (and don't
forget effects would also need "IDs") and you'll see what I mean.

~~~
k__
Couldn't a custom hook have a map of maps that keep track of this?

The first map gets the symbol that was passed to the custom hook as keys and
the maps inside that map would use symbols only the custom hook knows about.

I think your solution is superior in that is more concise and I at least think
I understand why you went that way. I'm just trying to understand why the
symbol approach wouldn't work.

~~~
danabramov
Yeah you could do this but this “breaks copy paste” (one of the flaws). We
want creating a custom Hook to feel exactly like extracting a function. It
should feel easy and you shouldn’t need to mess with maps and symbols.

~~~
k__
Okay, DX is an important selling factor, so your approach seems reasonable to
me.

~~~
danabramov
Runtime performance is another one. Map lookups aren’t free, especially if
there’s a whole bunch of them happening in every component on every render.

~~~
k__
Yes, the order restriction buys a lot of things rather cheaply.

And while I trust the React teams judgement, I teach people React and they
often question the "why".

------
danabramov
(I edited the post title to include “React” before the “Hooks” to
disambiguate. Might be worth editing the submission too!)

Hope you’ll enjoy reading it.

~~~
kmarc
I just briefly looked at the examples (and of course followed the twitter boom
about it), but what I am not getting is that to me it looks like since
useState() is against the principles of pure functional programming.

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?

~~~
asark
It's not a global object—it's an instance of the object for the component
you're using. The whole thing's a terrible OOP system in a language that
already has a built-in mediocre OOP system, which terrible OOP system is, in
the end, just a(n inefficient) pass-through to same built-in mediocre OOP
system.

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.

~~~
danabramov
_> The posters here wondering why you can't name them are on to something_

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.

~~~
asark
>The posters here wondering why you can't name them are on to something

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.

~~~
danabramov
I’d love to hear about your solutions but maybe don’t be so quick to dismiss
other people’s hard work as something to “help bloggers”. If we were chatting
face to face would you also behave like this?

We’re very open to good technical arguments but this isn’t one.

~~~
asark
> If we were chatting face to face would you also behave like this?

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.

~~~
danabramov
I empathize with your frustration of having to work with something you don’t
like (or feel is unnecessary). I would much prefer that people who don’t like
React aren’t forced to use it but that’s not how job market works. Sorry about
this.

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://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem)

[https://reactjs.org/blog/2016/07/13/mixins-considered-
harmfu...](https://reactjs.org/blog/2016/07/13/mixins-considered-
harmful.html#why-mixins-are-broken)

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.

~~~
asark
I entirely share your "ew, gross, no" re: mixins generally. That their being
added to React in the first place is part of this history is definitely
interesting.

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.

~~~
danabramov
Sorry but this is still pretty hand-wavy :-) I’d be happy to discuss a
specific “before” and “after” code example.

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.

~~~
asark
> 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.

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...](https://github.com/facebook/react/blob/master/packages/react/src/ReactHooks.js)

