Live data from Hacker News

Why Do React Hooks Rely on Call Order?

overreacted.io

41–50 of 115 posts

Re: Why Do React Hooks Rely on Call Order?

#41

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 passe…

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.

Re: Why Do React Hooks Rely on Call Order?

#42

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 passe…

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 somew…

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.

Re: Why Do React Hooks Rely on Call Order?

#43
post #14

Earlier quoted context omitted.

It's always strange when people act indignant about the fact that engineering a large frontend is difficult, like the world owes it to them for it to be easy. Frontend code is by nature highly repetitive, but each different unit has its own arbitrary tweaks because of the fact that people have to use it. This makes it very hard to abstract. There are a million visual frontend builders out there, and they are all terr…

>There are a million visual frontend builders out there, and they are all terrible, because you can never get them to do what you want. I disagree. I had worked with Visual Basic and it had a great balance of ease of use and flexibility. If you are not obsessed with the feeling that you need to see the underlying code of the UI, you can have a great visual builder. Of course you need to code the event handlers, that'…

Mobile UI builders can barely generalize over their own domain even when they are just targeting a specific platform.

That's not very high praise, to me. Look at all the code you still have to write just creating a table view on iOS. If I avoid writing code, then I'm stuck with stringly-typed identifiers hidden in sidebar menus which is even harder to debug.

The bottom line is that client development is hard. So hard that our tools for more focused platforms than web (like mobile) aren't even better, they just have different trade-offs.

Re: Why Do React Hooks Rely on Call Order?

#44
post #35

Earlier quoted context omitted.

Wouldn't symbols solve this issue?

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 diffe…

I guess changing call orders is an edge-case, so why optimize for it.

Re: Why Do React Hooks Rely on Call Order?

#45

(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.

Enjoying your posts, keep them up! Hooks look like a very powerful API for sharing pieces of functionality between components. You've probably heard this one a lot, but what bothers me a bit about hooks (especially useState) is that before, when you saw a component defined as a function, you could assume that it was just a function that renders something based on its props. However, I think it's a fair trade-off for such a powerful API.

Re: Why Do React Hooks Rely on Call Order?

#46

Earlier quoted context omitted.

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 somew…

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.

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

Yes, you're right. I was distracted with other stuff and meant just Symbol, without new. I'll fix it. Thanks.

As for the rest... Well, I don't really care much for React and many of the decisions they make. I don't like CSS-in-JS at all, and GraphQL... well, that one's nothing new.

Re: Why Do React Hooks Rely on Call Order?

#47
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..

Re: Why Do React Hooks Rely on Call Order?

#48
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 {width} {name}
  }
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.

Re: Why Do React Hooks Rely on Call Order?

#49
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

Re: Why Do React Hooks Rely on Call Order?

#50

Earlier quoted context omitted.

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 act…

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 u…

... or try MobX
Post reply on HN