Why React’s new Hooks API is a game changer

Finally we get rid of second rate coding patterns in React

Rudi Yardley
ITNEXT
Published in
6 min readOct 28, 2018

React’s new Hooks API allows us to finally share behaviour without any of the intrinsic problems that have plagued the community previously

Sharing behaviour between components

I have been developing with React since its early days and during that time there have been many attempts by both influencers, as well as the core team to improve the API and patterns developers are using to creating software. One of the biggest challenges we have had was how to share behaviour neatly between components to enable reuse or even just separation of concerns. Every single solution proposed up until this point had some problems associated with it.

Luckily React has just released a their new API for sharing behaviour in React components that solves many of the problems we have had in the past.

This is what it looks like:

An example of the new hooks API courtesy https://reactjs.org

First lets have a little look at how we got here…

Mixins and magic methods

When React was first released, classes were not available in ES5 so React shipped with its own class creation method, which included the ability to merge in a bunch of methods from an object into the component you create.

An example of the old mixin API

This unfortunately led to similar problems you find with classical inheritance; mainly indirection from magic undocumented methods appearing out of nowhere and being used on components. The developer has no idea what functionality is available to them and more importantly what is not.

This smell was so bad the React team decided to remove Mixins completely when they introduced a new ES6 class based API.

Things got better but there is still a problem

Both the more recent attempts at sharing functionality between Components, namely Higher Order Components and Render Props, have also fallen short on an API level for several reasons.

Higher Order Components still cause indirection

Higher order components (or HOCs) are an attempt at applying the Functional Programming concept of higher order functions to React components. The idea is that you alter your component by wrapping it in an outer component that provides behaviour, composing the original component and passing the behaviour’s results as new props to the original component. This is done in a similar fashion to the way higher order functions pass data via closures.

Higher Order component example courtesy https://reactjs.org

What’s great about higher order components is that you can see the data coming into the component as a prop. It is no longer magical like with Mixins.

However there are issues. The main problems with higher order components include:

  • They are complex to setup.
  • You can not distinguish between data that was coming from the HOC and the data that was passed to the component.
  • The HOC is external to the component yet the component remains dependent on the HOC. Remove the HOC and the component would not always work if it depends on the HOCs data.
  • You can end up with huge render trees as behaviour components contain render components.

Render props and the pyramid of doom

Render props are a relatively new trend and offer an answer to some of the dependency and indirection problems that HOCs can cause. They are created by enabling a component to accepts a function prop that it will use to render its children. This allows the component to provide a closure for its children as well as some behaviour and new data.

However they can be abused. See this (event though contrived, unfortunately rather typical) Apollo React example:

An example of render props pyramid of doom!

If you have ever worked with me you probably know my hesitation around using render props. I think it can be a useful pattern in certain contexts however it has a few major issues:

  • It declares false hierarchies ie. pyramid of doom.
  • Encourages passing inline functions to child components which if not checked can lead to performance problems.
  • Create confusing closure structures which should actually be inline.
  • Leads to very verbose component JSX

In fact class lifecycle methods also suck

Since its inception React has included various lifecycle methods for developers to hang code on based on particular execution times within the lifecycle of the component being rendered in React. Being able to support this asynchronous behaviour is why React components were modelled as classes to begin with. This model is simple and it provides an intuitive way to attach behavioural code to a Component.

There are problems however with this approach. What tends to happen in practice is that code relating to a particular functionality ends up being scattered all over the various lifecycle methods of the class and usually right next to code from unrelated behaviour. This commonly happens whether or not you are using HOCs or render prop components. Also by using classes you inevitably need to use the JavaScript this object which means you need to understand and take care of binding your handlers as you pass them around to child components.

React 14 introduced stateless functional components to resolve this but they did not provide ways to access lifeCycle methods which relegated them to only be used on components that would not grow into requiring complex behaviour

Enter the React “hooks” API

At ReactConf 2018, the React team announced their new hooks API. React’s new API attempts to solve these problems by making HOCs and render props obsolete. The new API allows for true state driven behaviour sharing while also:

  • Providing a way to get access to state managed props and be able to easily follow exactly where that state has come from.
  • Returning memoized functions avoiding performance penalty from downstream PureComponents
  • Not creating a pyramid of doom
  • Not touching props. What you pass into the component in JSX is what you get in props.
  • Not creating any magic behaviour methods.
  • Leading to simpler JSX that is more concerned with component rendering and less with behaviour.
  • Removing the performance overhead of wrapping components in layers.
  • Allowing for custom behaviours to be bundled off into their own functions that can be exported by libraries.

Example of the Hooks API

Here is an example of how to create a custom hook:

example courtesy https://reactjs.org

There are a few minor drawback to the new API

The main drawback to using the hooks API is that all the “hooks” methods must be run in the same order every time the component is rendered.

This means that you cannot call hooks functions within if blocks or loops within your functional component.

In fact when I first heard about this I was a little concerned. I don’t like the idea of hidden rules I have to follow. I think it means that new folks coming to the API will struggle to understand why their code is not working.

After thinking about this and reading through the docs for a bit I think I am beginning to understand why the React team has gone down this path.

The React team says they will support us with a suite of linting plugins. Not everyone uses linters however yet I would assume that they will at least attempt to include some kind of friendly runtime error as well eventually although detecting if a bit of code is in a conditional might be impossible at runtime. So this is a shame. Maybe over time the React team will work out clever ways to prevent trip ups for codebases that are not linted as well as on-board new developers to the API. After thinking about this and reading through the docs for a bit I think I am beginning to understand why the React team has gone down this path. Alternative syntax implementations will involve more boilerplate and to be fair this solution is actually rather ingenious.

Conclusion

The ideas presented in the hooks API is a boon for React developers. Finally we have a relatively baggage free API for developing React components. We no longer need to worry about refactoring from functional components to classes and can share behaviour without confusing indirection.

I look forward to seeing libraries such as ApolloClient and Redux develop their own hooks API components for implementing behaviour.

For more information you can check out their write up on the React website and watch the announcement demo below:

This article is a living document please reach out to me if you want to contribute or see anything inaccurate here.

You can follow Rudi Yardley on Twitter as @rudiyardley or on Github as @ryardley

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in ITNEXT

ITNEXT is a platform for IT developers & software engineers to share knowledge, connect, collaborate, learn and experience next-gen technologies.

Written by Rudi Yardley

Rudi Yardley is an independent senior full-stack software engineer and JavaScript/TypeScript/React specialist with over 19 years experience in industry.

Responses (10)

What are your thoughts?

The HOC is external to the component yet the component remains dependent on the HOC. Remove the HOC and the component would not always work if it depends on the HOCs data.

I do not really agree with this. From my point of view, the component being wrapped by the HOC is not “dependent” on it. This component expects a number of props without caring where they come from.
The HOC is just an easy way for the caller to have part of the (sometimes mandatry) props being set for him.

--

Okay. I think it’s time I give up React and start a food truck selling tacos. That’s something I’m not going to relearn anytime in my life. A taco is a friggin’ taco. It will always be, a taco. Sigh….

--

Thanks for your write-up Rudi. I’m new to React and trying to get my head into hooks before forming bad habits with Classes and HOCs. I found your post much more explanatory than others, and not just a re-hash of the React docs themselves.

--