< Back to articles

What I Don't Like About React Hooks

There has been a lot of discussions concerning React Hooks on Twitter recently and Dan Abramov is defending them pretty well. But since I have seen the API for the first time I can't get rid of the feeling that I just don't like them. Here is my reason why.

Disclaimer: I've been in the field since 2007 approx. and I work with React since early 2015. My background is strictly OOP which has had a strong impact on my opinion. If I had FP background, my thoughts might have been different.

The reason I don't like Hooks is the API. When you use React Class Components, all the features that are tightly coupled with them are encapsulated with them too. The mindset is pretty clear and straightforward. When you use React Hooks, nothing but UI is coupled with the component. Everything that should be logically coupled with the component is handled externally by React. React is exposing its implementation over the abstraction to make Hooks working. For me, Hooks break the encapsulation for the sake of being able to share more code.

The Abstraction

React is a Javascript library for UIs. It uses React Components and React Elements to abstract from the implementation of the UI. You are just describing the UI. Hence it uses a declarative programming paradigm. It is the job of React renderer (React DOM, React PDF, React Art, React Native) to know how to “physically” create the UI. The only thing the abstraction shares with an implementation is that the UI is tree based. React emphasizes composition over inheritance. Every React Component can be composed of other React Components.

HTML is the closes illustration of this tree-composed-by-components abstraction. And HTML is one of the “physical” renderings of the UI written in React.

Components and Elements

In React, you describe UI using React Components. The UI rendered by React Component is composed of React Elements (JSX syntax allows you to write them as XML-like tags) which are instances of other React Components. You can find some analogy in OOP with classes and objects as their instances but the core of these concepts is really different.

A React Component has following features:

  • can have its local state,
  • can share context with components in its subtree,
  • has some lifecycle methods so it can react to what is happening with it (it has been rendered for the first time, its state updated, it has been deleted from view etc.).

React Class Components

So far I was only describing the abstraction. Now you need to have a way to describe it in JavaScript. If you think about the features mentioned above, all of them are coupled with the component and should be encapsulated with it. So, React did a straightforward thing.

// Creating React Component via JavaScript class  
  
class Modal extends React.Component {  
  
 state = { open: false }  
  
 setOpen = (open) => {  
  
    this.setState({ open });  
  
 }  
  
 render() {  
  
    return open && ...;  
  
 }  
  
}

You write React Components as JavaScript classes. Thanks to them, you can preserve the encapsulation. But you never directly create any instance of these JavaScript classes. Instead, you create React Elements that are true instances of React Components. React Elements are plain JavaScript objects.

class Application extends React.Component {

 render() {

    // Creating an instance of Modal component using JSX

    // Here should be instantiated Modal with type="warning"

    return <Modal type="warning" />

 }

}

or

class Application extends React.Component {

 render() {

     // Creating an instance of Modal component using React API

     return React.createElement(Modal, { type: "warning }});

 }

}

Hmm, this can be confusing, I know. You use JavaScript classes just to hold the encapsulation but never care about their real instances. That is React’s job.

It is not equal to OOP but the principle of the encapsulation is used correctly to express the relation between React Components and their features. It is not the only possible way to describe React Components and Elements in JavaScript but I feel like it creates the best mental model. You don't have to care about what is happening between re-renders of component. Everything you need is stored in the component.

React Hooks

What would you do, if you wanted to share an implementation of one component with another? React had mixins but they were adding complexity into component implementation. OPP class inheritance is against React's composition. So programmers came up with HOCs. High Order Components accept React Component, enhance it, and return a new React Component. This encourages composition over inheritance but it can add a lot of complexity into the component tree.

Most of the time you want to share some code based on the features of React Components. So the React team came up with a solution that allows you to share the code without adding bad complexity into components or the component tree. The solution is called React Hooks.

React Hooks are functions that allow you to “hook” into the React features and use them. You use them directly in the render functions so you don't need the classes anymore. And you can use hooks to create custom hooks and share them with the community. It is really pretty neat! I was hooked too :).

But wait, the API?!

Here is an example of Modal component using local state to decide if it should be visible or not:

function Modal(props) {  
  
const [open, setOpen] = useState(false);  
  
...  
  
return open && ... ;  
  
}

So, via useState hook I hook the component into the React features and it can use the local state. But how does it work? How is it possible that in the first render it creates the state and in the second render it reuses the state it has created? Where is the state stored? Why is it not stored in the component? Is or isn't it coupled with the component? Shouldn't it be stored in the component?

There are so many questions about why and how it works and no straightforward mental model connected with the abstraction I have mentioned above.

How Does It Work?

How do React Hooks work then? I have already mentioned that React Components have some features and when you write React Components as JavaScript classes the features are encapsulated in the class. Well, that is a mental model, an abstraction that is far away from how React really works. For example, React never stores local state of a component in the component.

So what React Hooks do is uncovering the real implementation of React. If you want to work with React Hooks, you have to rethink everything you know about React. And you need to do one more thing. You have to accede to React being a runtime that handles React Hooks and makes them work. Let's say React Hooks are a new language feature. We don't care about how try/catch works, why should we care about how React makes Hooks work? This allows you to create an accurate mental model.

What I Don't Like About Hooks

I have said that there are more ways to describe the abstraction of React in JavaScript. React Class Components are one of them. But you are able to do the same things with React Functional Components + React Hooks (and + React Memo to be accurate). My problem is that the mental model created by Hooks separates the things that I feel should be coupled together. And you need 3 constructs to be able to do things you would normally be able to do with one.

And even though you admit React is a runtime that finds the right value of the local state connected to your component, or right lifecycle methods every time, you end up with taking care of things you never thought about when using JavaScript classes for React Components. For example, JavaScript closures can make a big mess when you are not careful.

Is it really worth it, uncovering React implementation to be able to share code? Is it really worth it, using fragile description of React abstraction? Can't it lead to more fragile and unreadable code? I think the following tweet describes my worries the best.

Conclusion

All I have described above are just my thoughts, something that came to my mind when I first saw React Hooks. React Hooks were not a love at the first sight. You don't have to agree with me and I think that is OK. It is important to discuss things. Especially the things that you think are important.

And even though I don't like React Hooks API, I can understand the reasons why it is made this way. And the idea of being able to share the code of one component with another easily and without the need of additional composition is great. Another great thing is that Hooks force you to think about edge cases early which can make your components less buggy. I guess I just need to get used to the new mental model and get over the decoupling that pisses me off the most.

Maybe this article even helped you to understand Hooks background better. Or understand React better. If you are still not sure about how Hooks work or if you like them, try overreacted.io. Dan is giving out all he can to help us understand Hooks and React ?.

Marek Janča
Marek Janča
Frontend DeveloperManča is our frontend master, a legend in web engineering from Krkonoše. He often disappears to Finland and likes coffee, art, architecture, music, books and movies.

Are you interested in working together? Let’s discuss it in person!

Get in touch >