Pragmatic articles on software development and management

The biggest lies about React Hooks

Published on by fakiolinho

I tend to listen and read really a lot about the meaning of React Hooks and how they help us to win the fight against evil classes that tend to pollute our codebase and blah blah blah. So guess what? This is a big lie.

import React, { useState } from 'react';  

function Toggler() {  
  // Declare an "on" state variable and a method to toggle it :)  
  const [on, setOn] = useState(false);  

  return (  
    <button onClick={() => setOn(on => !on)}>  
      {on ? 'ON' : 'OFF'}  
    </button>
  );  
}

Why Hooks?

Hooks were not invented to kill classes. Hooks became part of our toolset so we can create and share small, re-usable and maintainable pieces of logic in our applications without nesting some more into the components tree. No mixins, no higher-order components, no render props craziness. Just Hooks 😉

Ok but what about classes?

To be honest, the problem that Hooks solve is much more important than dropping classes but we cannot ignore the big change that was introduced regarding their usage.

They are definitely not required anymore to provide some magic and this is a remarkable fact, but this is just a nice consequence with the new API.

This is why the React team has officially declared that classes are not dropped or something and new versions will keep on supporting them.

From React webpage:

There are no plans to remove classes from React — we all need to keep shipping products and can’t afford rewrites. We recommend trying Hooks in new code.

So I can drop classes for good right?

Nope, you can’t. There are still some cases where you need classes. So far lifecycle hooks, like componentDidCatch and getSnapshotBeforeUpdate are not supported by Hooks so if you really need these goodies you have to go with classes API. These are said to become part of the Hooks API really soon.

Apart from that, classes play nicely with Hooks in the components tree, but you cannot use a Hook inside a class and this might force you to create a couple more classes down the road 😬.

Cool, so what do I choose?

Go with Hooks of course for your new components, since they make it easier to share logic while using simple functions. As we discussed above, classes might be needed in some occasions and this is pretty normal.

From React webpage:

In the longer term, we expect Hooks to be the primary way people write React components.

Render props and HOCs are not relevant anymore?

Hmm, no they still are. You can definitely keep on using them and even combine them with Hooks in your components so you can implement progressive enhancement. There is nothing that prohibits this, but Hooks of course will help you to simplify your components without all the extra nesting that these patterns introduce by definition.

From React webpage:

There is still a place for both patterns…But in most cases, Hooks will be sufficient and can help reduce nesting in your tree.

Do I have to test my components in a different way?

Hmm, that is a really good question. Of course not, but if your tests are error-prone by using let’s say the component’s instance (sorry enzyme 🤓), then you definitely need to refactor them.

From React webpage:

From React’s point of view, a component using Hooks is just a regular component. If your testing solution doesn’t rely on React internals, testing components with Hooks shouldn’t be different from how you normally test components.

Nevertheless, there are some things you should be aware of, regarding tooling and instrumentation for your tests.

React offers ReactTestUtils.act() to test our components but enzyme doesn’t support Hooks testing entirely at the very moment while react-testing-library does. This might be an issue for you especially if you are not aware of the latter. Also this might be a ringing bell about the plan you are going to follow regarding Hooks in general.

React team promotes react-testing-library usage directly in the Hooks docs as a best practice.

From React webpage:

To reduce the boilerplate, we recommend using react-testing-library which is designed to encourage writing tests that use your components as the end users do.

it('can render and update Toggler', () => {  
  // Test first render and componentDidMount  
  act(() => {  
    ReactDOM.render(<Toggler />, container);  
  });  
  const button = container.querySelector('button');  
  expect(button.textContent).toBe('OFF');  

  // Test second render and componentDidUpdate  
  act(() => {  
    button.dispatchEvent(new MouseEvent('click', {bubbles: true}));  
  });  
  expect(button.textContent).toBe('ON');  
});

Conclusion

Don’t get crazy about the non-existing battle between Hooks and classes. We need both of them at the very moment to ship a robust client-side application in production and that is all that matters.

Embrace Hooks and start using them for the right reasons by simplifying your applications codebase and making it much more readable and maintainable.

Last but not least, it is a great time to start playing around with react-testing-library and get rid of some sins and bad practices of the past. Cheers!!


Did you enjoy this article? Don’t forget to hit 💚 to share some love and check our next workshop on React Hooks!

React Hooks fundamentals


If you found this interesting, you can follow me on Twitter at @fakiolinho. Check out some of my other articles below: