Introduction to React Hooks

Introduction to React Hooks

·

6 min read

React hooks are something that everyone uses at the moment. A nice feature that no one seems to understand what they are. Each time I ask someone what are hooks, usually response is they are useState and useEffect functions. Those are examples of hooks, but it doesn’t answer what they are. And in this post, I am trying to simplify what they are.

Background

When I started working with React, I loved writing class components. Even when functional components started becoming popular, I still kept writing classes. But they do suffer from some critical issues. Class components are harder to minimize. There is much boilerplate code, and don’t get me even start on the issue with this keyword. Functional components are much cleaner, but there was a problem of access to the state and lifestyle components. It is where React hooks come. They enable access to React features from function components. And the following are two examples of hooks you get with React and how they make your life easier.

State hook

For accessing to component state, there is the useState hook. With the class components, you would need to use a whole set of lifecycle methods. First, you would need a constructor to set up the initial state, then making functions to update the state. Each time you create those functions, there is an issue with this. I still haven’t met junior, who didn’t ask me what this is when they see the bind method. Well, many more senior developers often ask the same question. With useState, it is only one function. You pass its initial state. As a return, you get a variable containing a value and a function you can use to update it. Executing this function also triggers the re-render of the component—much cleaner and more straightforward code.

Class component with one state variable:

import React, {PureComponent} from 'react';

class Counter extends PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            counter: 0
        }

        this.increment = this.increment.bind(this)
    }

    increment() {
        this.setState({counter: this.state.counter + 1})
    }

    render() {
        return (<div>
            <div>{this.state.counter}</div>
            <div>
                <button onClick={this.increment}>Increment</button>
            </div>
        </div>)
    }
}

Function component with hooks:

import React, {useState} from 'react';

function Counter() {
    const [counter, setCounter] = useState(0);

    const incrementCounter = () => setCounter(counter + 1)

    return (
        <div>
            <div>{counter}</div>
            <div>
                <button onClick={incrementCounter}>Increment</button>
            </div>
        </div>
    )
}

Side effects hook

Saying side effects hook doesn’t mean much. But when you have a task you want to execute after the component mounted, this is the hook you want to use. Maybe you want to register some event listeners, subscribe to API, unsubscribe from API, or any other action that should not be inside the main component body. This hook is the place to do it. And suppose you are coming from a class component background. In that case, if you had some actions in componentDidMount, componentWillUnmount, and similar function, there is a high chance it is a place for useEffect hook. This hook needs at least one argument a function to execute. And if you have some cleanup action to do, this function can also return a function that would do that.

Subscribe to API example

import React, {useEffect} from 'react';

function Chat() {
    useEffect(() => {
        ChatAPI.subscribe();

        return () => {
            ChatAPI.unsubscribe();
        }
    });

    return <div>Chat</div>
}

There are more things about both useState and useEffect hook to explain. One of them is executing useEffect conditionally. But that is not the topic of this post. The goal is to show how they enable access to React features and in a much cleaner way.

Pros and cons, but mainly pros

The only real limitation of hooks is that they need to be unconditional. That means you can’t put them inside of an if statement, and you can’t create a state at a later point in time. Also, many developers place way too much logic inside of it. That is not needed as you can have multiple of the same hook. With the class component, you would need to place registering all APIs into componentDidMount or similar. With hooks, you can have multiple useEffect hooks in the same component—one for each task you want to perform. And last, since hooks are just functions, they are much easier to exclude and reuse. Export it and import where it is needed. That means cleaner, more reusable, and more straightforward to test code. No one can object to that.

Wrap up

Hooks don’t introduce some new functionality you couldn’t do with class components. They give you a new and clean way to do it. Above, I used two hooks to illustrate that, but there are other hooks, and you can create your own. You can find a full list of built-in hooks on the React documentation page. There are many other resources on hooks. An excellent source for understanding is the React Conf talk by Sophie Alpert, Dan Abramov, and Ryan Florence. But I also suggest the Codú Community channel where Niall has a whole series of videos on hooks. You can watch the introduction one here.


For more, you can follow me on Twitter, LinkedIn, GitHub, or Instagram.