A Critique of React Hooks

栏目: IT技术 · 发布时间: 4年前

内容简介:I want to preface this critique by saying I think that hooks are not all bad. If I were starting a new react project today I would still use them despite all these flaws. However, that doesn't make them immune to criticism. Given their design, I think ther
A Critique of React Hooks

I want to preface this critique by saying I think that hooks are not all bad. If I were starting a new react project today I would still use them despite all these flaws. However, that doesn't make them immune to criticism. Given their design, I think there are a number of factors limiting their longevity and I won't be surprised if Facebook comes out with The Next Greatest Thing™ to address some of their shortcomings.

1. More Stuff to Learn

The first and easiest gripe with hooks is simply that they're another thing to learn. I was fortunate to get into frontend development at a simpler time where you could just dump jQuá on the page and call it a day. Then as new complications came along I could learn them incrementally. Nowadays there is just so       much       to       learn . If I was a new developer and saw that chart I would want to go home and rethink my life.

Learning new things is good though! We should be learning all the time! The problem with learning about hooks is that they're not generally applicable knowledge about computing or programming. They're a React-specific thing. In 5-10 years when you're programming something completely different your knowledge of hooks will be completely obsolete. Whenever possible, you should pick learning about generally applicable thing A over very specific thing B so that your knowledge can compound and pay dividends.

2. They Don't Interoperate With Class Components

If you're starting a new project that doesn't use class components you can GOTO 4 , but read on if you're in the camp of working on an app from the time before hooks.

Say you're working in a project that's been around for a while and it's 50% FunctionComponent 's and 50% class components. Now it's time to implement a new feature which you think would be a perfect use of a custom hook to do the heavy lifting. This works great in the original FunctionComponent that uses it, but now you need to use that feature in a class component. What do you do?

There are a few options, but they all have drawbacks. First, you could reimplement the feature without hooks but I hope you don't do that. Alternatively, you could create a HOC to wrap your component and pass down the hooks functionality. This creates a lot of boilerplate and doesn't compose well though. The only sustainable option is to suck it up and convert that class component to a FunctionComponent . Depending on how much stuff is going on in that component, this can take a while and there's a non-trivial chance of introducing a bug.

This is a problem that lessens in time as more of your app is converted of course, but can be a real challenge to being productive when each time you touch a component you have to refactor it.

3. Ecosystem Challenges

The React docs claim hooks are "Completely opt-in" and "you don't have to learn or use Hooks right now if you don't want to". This seems a little disingenuous to me. Code doesn't change but the world around it does.

As a library author, you're forced to make some choices in the now fractured ecosystem. Do you add support for hooks? Do you also maintain support for class components? For how long? This is a hard question to answer, especially if the library leaned heavily into HOC's .

As a library consumer, what happens when you need to upgrade a library but it made the choice to only support hooks? As the ecosystem evolves and adopts hooks you'll be coerced more and more into using them. This is another argument for reducing your dependencies but that's a story for another day.

4. The Rules of Hooks Limit Your Design

I'm assuming anyone who's read this far knows about the Rules of Hooks . The reason for the rules makes sense given that React uses call order to maintain state but this constraint can really limit how you organize and optimize your code.

In a recent example, I was building a hook that returns a lookup table where many of the values in the table were hooks themselves.

function useLookupTable(param){
    return {
      a: {
        default: useADefault(param)
      },
      b: {
        default: useBDefault()
      },
      . . . many more entries
    }
  }

To avoid returning a big new object every time this hook is called I wanted to memoize the value. Lets try wrapping it in a useMemo :

function useLookupTable(param){
    return useMemo(() => {
      return {
        a: {
          default: useADefault(param)
        },
        b: {
          default: useBDefault()
        },
        . . .
      }
    })
  }

Oops. React Hook "useADefault" cannot be called inside a callback. So let's pull all the hooks out and include them as dependencies:

function useLookupTable(param){
    const aDefault = useADefault(param);
    const bDefault = useBDefault();
    . . .

    return useMemo(() => {
      return {
        a: {
          default: aDefault
        },
        b: {
          default: bDefault
        },
        . . .
      }
    }, [aDefault, bDefault, . . . ])
  }

We've now got rid of the error (and introduced an annoying number of temporary variables) but we're still returning a new table every time. Why? Oh, it's because one of the values is a new array which fails the dependency equality check every time. Enforcing each of these useXDefault hooks to return a stable value (like with a useRef ) seems like a bad call since it would overly complicate them, and even if I did, as the table grows (and if each entry has multiple hooks) the dependency array soon gets out of control.

In this case I think the best solution is to refactor all these hooks to not be hooks and just regular functions that take their dependencies explicitly so that you can call them inline like in the second example and the dependency array for useMemo is manageable.

These sorts of battles with how you have to organize your code in a world of hooks is common, and it can take a lot of iteration, thought, and time to come up with a design that feels good.

5. They Complicate Control Flow

Using a few useState hooks is pretty easy to understand, but once you start needing to use all the other kinds of hooks up and down the component tree it becomes very difficult to follow the execution order of your code. How well can you reason about code if you don't understand the order it's executing in?

Here's a little quiz to see how well you can follow some toy examples.

If you aced it, congrats! I'm guessing you either ran them yourself or you had to sit back and scratch your head a bit. These are certainly contrived examples, but we all should be able to agree that simpler and less magical code is easier to work with than the alternative.

In Conclusion

I'm not asking you to never use hooks or remove them from your project. As I said in the intro, I would still use hooks in a new project, and I think they do improve the prior situation of HOC's creating component hierarchies deeper than the Mariana Trench. But I also think they're not the "Computing Promised Land". It might be a while before we get there though.

So until then, just use them judiciously.

P.S. Library authors, please try to keep things simple!

Cross posted to https://medium.com/indigoag-eng/a-critique-of-react-hooks-6de10e8f14e1

Back to home More blog posts

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

产品型社群

产品型社群

李善友 / 机械工业出版社 / 2015-3-1 / CNY 69.00

传统模式企业正在直面一场空前的“降维战争”, 结局惨烈,或生或死。 传统模式很难避免悲惨下场, 诺基亚等昔日庞然大物轰然倒塌, 柯达发明了数码成像技术却依然破产, 新商业的兴起到底遵循的是什么模式? 微信轻而易举干掉了运营商的短信业务, “好未来”为何让传统教育不明觉厉? 花间堂为什么不是酒店,而是入口? 将来不会有互联网企业与传统企业之分, ......一起来看看 《产品型社群》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

随机密码生成器
随机密码生成器

多种字符组合密码

html转js在线工具
html转js在线工具

html转js在线工具