Sitemap
JavaScript in Plain English

New JavaScript and Web Development content every day. Follow to join our 3.5M+ monthly readers.

Follow publication

Why React hooks?

--

Press enter or click to view image in full size
Photo by Joanna Kosinska on Unsplash

If you’re a React developer it’s hard to escape the ever present discussion of React hooks. For those that are uninitiated, hooks are a series of baked-in React functions that allow developers to do everything that they can do in class components inside functional components.

But why the switch? If class components can do all the things that we want them to do — initialize state, set state, access the component life cycle, create context, invoke refs, etc. — then why would we ever want a way for our dumb, presentational components to work this way as well? What’s so special about functional components?

Well, it turns out there are a few reasons why using hooks present benefits for developers. The first is large class components can be unwieldy to work with. Engineers that have worked on big applications, centralized, stateful components can balloon in size, often times with either the same or similar logic spread across component life cycle methods. The second is method reuse. Reusing component methods, especially complex logic, relies on design patterns like higher order components or render props which in turn require developers to reorganize their component hierarchy and can lead to a mess of wrappers. Finally, class syntax is confusing for both humans and machines and can lead away from the pure functional design pattern React seeks to maintain.

So how do hooks solve these problems?

Component Size

When it comes to the scale of components, hooks abstract away much of the repeated functionality within life cycle methods with useEffect and flattens state initialization with individualized useState calls. One useEffect hook, for example, can do the work of 3 life cycle methods: componentDidMount, componentDidUpdate, and componentWillUnmount. By specifying an optional dependency array you can tell useEffect to look for changes in a specified state reference and run the effect again- effectively equivalent to componentDidUpdate. By specifying an empty dependency array you tell useEffect to only run once- componentDidMount. When the component is removed from the DOM and you need to perform some data cleanup- say clearing an interval or preventing an api call- you can give useEffect a callback in a return statement that will be run on unmount- componentWillUnmount. All of this work can be accomplished with one useEffect call, making it an extremely powerful way to account for side effects!

Method Reuse

When it comes to reusing component logic elsewhere within our app, the traditional way we generalize these scenarios is either by using render props or HOCs (Higher Order Components).

Render props works by passing a customized callback with individualized JSX down as props to our component. We use this when we want the same data to be reusable across multiple instances of our rendered component. For example, if we wanted to track our mouse position through one component but wanted to do different things with that data (like display the position in a <p> tag rather than a <h1> tag) we can do that by specifying render props with that customized JSX.

HOCs (Higher Order Components) function by creating either a wrapper component or a function that returns a wrapper component which gives that wrapped component access to some data or functionality. We would want to use this if multiple components are doing similar, but slightly different work, like grabbing some data from the same source but using different methods. Think Redux’s connect() function where it connects the wrapped component to our store. There might be multiple components that need to connect here but with different needs for state and dispatch methods. So we can provide customized mapStateToProps and mapDispatchToProps functions to our connect HOC to give our wrapped component individualized data.

While these patterns have worked pretty well for class components, they come with drawbacks. In particular they require a developer to rewrite their component heirarchy and can lead to the 9th circle of wrapper hell. Hooks’ alternative is to allow our hooks calls to be shared across components in the form of custom hooks. Custom hooks are just composable functions that can be exported and shared across components like any other function. By composable we mean the ability to take multiple parts (like useState and useEffect calls), combine them into a reusable pattern, and abstract them away into their own separate function. This pattern would be impossible in a class component since doing something as simple as fetching data or instantiating state could not be separated from the class methods in which they’re being invoked.

Performance and Confusion

Finally, there are minor concerns over performance within class components. At React Conference 2018, when React Hooks were unveiled, it was pointed out that class components are difficult for both machines and people to understand. Since class syntax is simply a syntactic sugaring for JavaScript’s prototypal inheritance, classes don’t work in the same way that other programming languages do. As a result, the React team has noticed problems with minifying class components in production builds and there’s been inconsistency when implementing hot module reloading. Additionally, it can be difficult for engineers, especially those new to class syntax, to understand how the binding of the ‘this’ keyword works or other class nuances like the purpose of calling super() inside the constructor.

Since hooks allow us to use all of the same class component functionality inside functional components we’re able to boost the performance of our React code. Additionally, hooks have a clean syntax that is more inline with not only React’s pure functional design, but also their focus on just JavaScript. One of React’s main differences between other component-based front-end libraries like Vue, is its coupling of html, css, and JavaScript through JSX and css modules. This means, if you’re an expert in JavaScript, then you’re an expert in React (give or take implementation details) as opposed to Vue’s template structure that relies on splitting files between HTML, CSS, and JS like the good old days of jQuery and vanilla JavaScript DOM manipulation.

While the slight performance boost of functional components is nice, performance should not be the main reason why you use hooks. Hooks do NOT add any functionality within React that wasn’t already there. It’s primary purpose is simply to elevate functional components to the same level as class components, in turn allowing for a better DX (Developer Experience) through cleaner, more maintainable code, better method reuse across components, and an easier, more declarative way of using state, life cycle methods, and a whole host of other React functionality like refs, memoization, reducers, and context.

That being said, I’ve had colleagues who have found hooks to be conceptually opaque in grasping, especially when it came to understanding useEffect, useState, or useContext. For instance, it can be difficult to see how you should combine your varying logic in your life cycle methods into a singular function call. So recently, a group of engineers and I created a CLI templating tool called Hookd to instantly convert class components to functional components with hooks. We’ve just launched our Alpha version and would love contributors and feedback. If downloading a CLI is not your style we also have a client where you can c/p your components to find the hooks equivalent.

Clean Your Code, Clean Your Mind

Ultimately, using hooks seem to be more than just a developer fad. It allows developers the power to clean up their code and in turn clean up their minds. It shouldn’t be understated how important clean and declarative code can help produce more bug free, modular, and maintainable applications. Until machines start coding for us, we’re under very human constraints of following lines of logic that make sense to us, and other humans that we have to communicate with.

--

--

JavaScript in Plain English
JavaScript in Plain English

Published in JavaScript in Plain English

New JavaScript and Web Development content every day. Follow to join our 3.5M+ monthly readers.

Devon Vaccarino
Devon Vaccarino

Written by Devon Vaccarino

Fullstack software developer who is fixated on the depth of React and the Hooks Revolution. Beatbox master and salsa/bachata dancer.

Responses (7)