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

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

查看所有标签

猜你喜欢:

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

智能商业

智能商业

曾鸣 / 中信出版集团 / 2018-11 / 68.00

《智能商业》由马云作序推荐。《智能商业》是阿里巴巴集团前总参谋长曾鸣,对互联网时代的重要趋势做出革命性解读的作品,披露了其对于未来商业模式的思考和判断。 2006年,曾鸣教授加入阿里巴巴集团,参与阿里巴巴集团及各重要业务线,如淘宝、支付宝、阿里云计算、菜鸟等的发展,被业界称为阿里的“军师”。 基于在阿里巴巴集团十几年的实践经验,以及对互联网、大数据和人工智能的深入思考,曾鸣教授在《智能......一起来看看 《智能商业》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

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

html转js在线工具