1. 9

  2. 6

    What I don’t get about this criticism is why the obvious solution is not sufficient. If one thinks the lifecycle methods componentWillReceiveProps and componentWillMount etc are sufficient, simply create hooks mirroring those methods: useComponentWillReceiveProps and useComponentWillMount etc. This should be

    • nearly exactly equivalent to the lifecycle methods,
    • a very light-weight patch, and
    • avoids a rewrite to get the lifecycle methods.
    1. 2

      This is the troubling part of React Hooks model - you really want a taint-tracking typechecker to enforce safety. The Eslint rule-of-hooks does a pretty good job of this in-practice (have you tried it out @gecko?) but it doesn’t bring the piece of mind that having taint tracking in Flow or Typescript would.

      1. 2

        To be honest, that is a problem with class-based components too. Perhaps even more so – keeping the same domain logic in sync across multiple different methods is hard.

        The difference is that hooks make the hard things explicit and obviously there, which is what we want for hard things. With class-based components the difficulty is implicit, which is a dangerous state of affairs.

        1. 1

          The Eslint rule-of-hooks does a pretty good job of this in-practice (have you tried it out @gecko?)

          Yeah; it’s okay. The main problem I’ve noticed is unnecessary dependencies getting added, either due to a genuine bug (I’ve seen it ask me to shove something like window into the dependency list) or because you forget to remove it once you alter the effect. Depending on which it is, the real dependencies get obscured, or you end up running the hook when you don’t actually need to. (This can also be a problem because, unless I’m mistaken, dependencies aren’t compared via deep equality, so it’s on you to make sure the values change in a way React will notice.) As you point out, compiler-supplied taint tracking would probably go a long way here.

        2. 1

          Yes, but with hooks you actually can use useEffect as the foundation for more specific hooks. I agree that when I see useEffect by itself it’s hard to understand what it’s supposed to do, so whenever I start to have readability problems I simply extract that functionality into a hook.

          With custom hooks you can also group functionality together in a way that is impossible to do with lifecycle methods. When you have to perform several effects at mount or unmount or when props change you have to spread them all over the lifecycle methods together with other unrelated functionality, which becomes really hard to read. And yes, you could put that stuff into separate components, but a lot of times I find I have state that belongs together, and splitting it up would just make it harder to understand the big picture…

          I don’t know, I really don’t see the point of using class components. I find the syntax very distracting, I don’t find the lifecycle methods very intuitive and I think hooks enable me to write more correct code, because achieving the same things with class components was much more complex and required much more bookkeeping.

          I don’t think I ever implemented promise cancellation in a class component, because every single time I’d have to add a property to the class, name it appropriately, and remember which lifecycle hooks I’m supposed to use, all of this interspersed with all sorts of other state and logic and spread over no less than four methods, while with hooks I can put that in a custom hook once and use it anywhere I want with no readability cost.