Popular React Hook libraries
Tags: react, javascript
Published: 2019-10-03 19:07:55

---
title: Popular React Hook libraries
published: true
tags: react, javascript
canonical_url: https://blog.logrocket.com/popular-react-hook-libraries/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/q8s6gedctpdvpf32xx4y.png
---
**Written by [Raphael Ugwu](https://blog.logrocket.com/author/raphaelugwu/)**✏️

The journey of the React ecosystem has really been an interesting one. Since the advent of features like [time slicing and suspense in React 16.3](https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html), we’ve had a series of interesting concepts from the awesome React team but none have been as eye-catching as React Hooks which got its first stable release in [React 16.8](https://reactjs.org/blog/2019/02/06/react-v16.8.0.html).

Offering a cleaner way to write code while not having to worry about backward compatibility issues means it’s probably safe to say that Hooks are here to stay. In this blog post, I will depict how Hooks are _lifesavers._ I will illustrate a couple of use cases that will feature popular React Hook libraries – both mainstream and custom (created by enthusiasts like you and me). Let’s get started.

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## What are React Hooks?

Basically, Hooks provide a medium for passing state and properties without having to create class components. Adopting a function-based approach, with Hooks we can separate our logic from our UI such that it can be reused in other parts of our application as well. Take a look at both code samples below:

```jsx
import React, { Component } from "react";
class MovieButton extends Component {
  constructor() {
    super();
    this.state = { buttonText: "Click to purchase movie tickets" };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState(() => {
      return { buttonText: "Enjoy your movie!" };
    });
  }
  render() {
    const { buttonText } = this.state;
    return <button onClick={this.handleClick}>{buttonText}</button>;
  }
}
export default MovieButton
```

The gist above shows how the internal state of `MovieButton` is changed by `setState` when the button is clicked. Using Hooks, this internal state change can be depicted without having to depend on classes, constructors or setState:

```jsx
import React, { useState } from "react";
export default function MovieButton() {
  const [buttonText, setButtonText] = useState("Click to purchase movie tickets");
  function handleClick() {
    return setButtonText("Enjoy your movie!");
  }
  return <button onClick={handleClick}>{buttonText}</button>;
}
```

I chose to show `useState` first because it’s the [first hook introduced to the React ecosystem](https://reactjs.org/docs/hooks-intro.html). `useState` is used to manage a component’s local state and preserve it between re-renders. What’s fascinating is that the component doesn’t have to be an ES6 class component – a basic JavaScript function is fine and we accomplish the same thing while reducing our codebase by ten lines. Implement `useState` by including a pair of variables – one to represent the actual starting state of your component and the other representing what you want your component’s state to be updated to.

## Mainstream React Hook libraries

### State and data fetching

Let’s say I wanted to create an application using just Hooks. Most likely, I would have to fetch data at some point. A good approach would be to begin with defining state wherever it needs to be defined. I’ll start by creating a component and fetching data from an API to be rendered by this component:

```jsx
import React, { useState, useEffect } from "react";

const URL = "https://api.punkapi.com/v2/beers";
export default function Landing() {
  const [beer, setBeer] = useState([]);
  useEffect(() => {
    fetch(URL)
      .then(response => response.json())
      .then(beer => setBeer(beer));
  });
}
```

This brings us to the `useEffect` Hook. The `useEffect` Hook lets you handle lifecycle events directly inside function components. Activities such as setting up a subscription and data fetching which we would use lifecycle methods such as `componentDidMount()` to accomplish are now handled via `useEffect`. According to [React’s documentation](https://reactjs.org/docs/hooks-effect.html):

> useEffect serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React class lifecycle methods, but unified into a single API

So in the above example instead of having a class component, I created a function and called the `fetch` method inside `useEffect`. There’s also no need to use `this.setState` to update state here as I created `setBeer`, a random function extracted from the `useState` Hook.

If you’ve been following up to this point and you try to run the application with the code sample above, you should encounter a very ugly infinite loop:

{% youtube 5w0snGY1w2Q %}

Why? `useEffect` serves the same purpose as `componentDidMount`, `componentDidUpdate` and `componentWillUnmount`. Because `setBeer()` updates the state of `beer` after every data fetch, the component is updated and `useEffect` goes ahead to fetch data again.

To avoid this bug, we need to specify that we only want to fetch data when the component mounts by providing an empty array as a second argument to `useEffect`:

```jsx
import React, { useState, useEffect } from "react";

const URL = "https://api.punkapi.com/v2/beers";
export default function Landing() {
  const [beer, setBeer] = useState([]);
  useEffect(() => {
    fetch(URL)
      .then(response => response.json())
      .then(beer => setBeer(beer));
  }, {});
}
```

### Form handling

Through custom Hooks (and there are tons of them in the ecosystem right now), React lets you reuse and share little bits of logic. As a rule of thumb, when there’s a lot of logic in a component, it’s a sign that you should refactor it and distribute some of the logic to avoid having bloated components. Let’s rely on custom Hooks to create some sort of interactivity with our app – say like a form where users can submit their data. [react-hook-form](https://www.npmjs.com/package/react-hook-form) is a library built entirely with Hooks and provides form validation. We’ll include it in our application like we would install an npm package:

```jsx
npm i react-hook-form
```

And then import the custom Hook we need – `useForm`:

```jsx
import React from "react";
import useForm from "react-hook-form";

const active = {
  fontSize: "15px"
};
export default function Purchase() {
  const { register, handleSubmit, errors } = useForm();
  const onSubmit = data => {  // upload the data retreived from the form to a database, return value to a user, etc
    console.log(data);
  };

  return (
    <div>
      <form onSubmit={handleSubmit(onSubmit)}>
        <label>Full Name</label>
        <input name="fullname" ref={register} />
        <label>Beer Name</label>
        <input
          name="beerName"
          ref={register({ required: true, maxLength: 10 })}
        />

        <select style={active} name="Title" ref={register({ required: true })}>
          <option value="">Select...</option>
          <option value="six-pack">Six Pack</option>
          <option value="twelve-pack">Twelve Pack</option>
        </select>
        <label>
          <input type="checkbox" placeholder="+18" name="+18" ref={register} />I
          am 18 and above
        </label>
        {errors.beerType && <p>This field is required</p>}
        <input type="submit" value="Pay Here" />
      </form>
    </div>
  );
}
```

An overview of how this works:

{% youtube ojVqNiAJdGM %}

## Routing

The application is gradually expanding, at this point, it would be great to include what every app with multiple components needs – routes. We’ll make use of `hooksrouter` – an awesome library that exports a custom hook `useRoutes`:

```jsx
npm i hookrouter
```

`useRoutes` evaluates a predefined route object and returns a result when the routes match:

```jsx
import React from "react";
import Purchase from "./components/Purchase";
import Landing from "./components/Landing";
import HomePage from "./components/HomePage";
const Routes = {
  "/": () => ,
  "/purchase": () => ,
  "/landing": () => 
};

export default Routes;
```

This trims down the excessive code we have to write when using traditional react Router as we would render the `<Route/>` component for all the individual routes in our app and pass props in them. Now, all we have to do is import the `Routes` component and pass it to the `useRoutes` Hook:

```jsx
// index.js or where you choose to render your entire app from
import { useRoutes } from "hookrouter";
import Routes from "./router";

function App() {
  const routeResult = useRoutes(Routes);
  return <div>{routeResult}</div>;
}
```

Let’s see what navigating through the app feels like:

{% youtube 0shA2ukTvsY %}

## Handling complex state management

Of course `useState` is used to manage state but what if your app grows in complexity and you have to deal with multiple state transitions in one state object? This is exactly what the `useReducer` Hook is useful for. `useReducer` is preferred when you have to handle data in multiple objects or arrays and also keep this data maintainable and predictable. To depict the `useReducer` Hook, I’ll add a page with some multiple state architecture to the app – maybe a place where our users can create their own beer recipes:

```jsx
import React, { useReducer } from "react";

const myStyle = {
  color: "white",
  fontSize: "20px"
};

export default function Recipe() {
  const initialState = {
    RecipePrice: 0,
    recipe: {
      price: 100,
      name: "Oompa Loompa",
      image:
        "https://res.cloudinary.com/fullstackmafia/image/upload/v1568016744/20110111-132155-Homebrew-Grain_uihhas.jpg",
      ingredients: []
    },
    stockpile: [
      { id: "1", name: "Extra Pale Malt", price: 10 },
      { id: "2", name: "Ahtanum Hops", price: 6 },
      { id: "3", name: "Wyeast 1056", price: 8 },
      { id: "4", name: "Chinook", price: 5 }
    ]
  };
  const reducer = (state, action) => {
    switch (action.type) {
      case "REMOVE_ITEM":
        return {
          ...state,
          RecipePrice: state.RecipePrice - action.item.price,
          recipe: {
            ...state.recipe,
            ingredients: state.recipe.ingredients.filter(
              y => y.id !== action.item.id
            )
          },
          stockpile: [...state.stockpile, action.item]
        };
      case "ADD_ITEM":
        return {
          ...state,
          RecipePrice: state.RecipePrice + action.item.price,
          recipe: {
            ...state.recipe,
            ingredients: [...state.recipe.ingredients, action.item]
          },
          stockpile: state.stockpile.filter(x => x.id !== action.item.id)
        };
      default:
        return state;
    }
  };

  const [state, dispatch] = useReducer(reducer, initialState);

  const removeFeature = item => {
    dispatch({ type: "REMOVE_ITEM", item });
  };

  const addItem = item => {
    dispatch({ type: "ADD_ITEM", item });
  };

  return (
    <div className="boxes" style={myStyle}>
      <div className="box">
    <h4>Ingredients Stockpile</h4>
        <figure>
          <img width={"300px"} src={state.recipe.image} alt="my recipe" />
        </figure>
        <h2>{state.recipe.name}</h2>
        <pre>Amount: ${state.recipe.price}</pre>
        <div className="content">
          <h5>Added ingredients:</h5>
          {state.recipe.ingredients.length ? (
            <ol type="1">
              {state.recipe.ingredients.map(item => (
                <li key={item.id}>
                  <button
                    onClick={() => removeFeature(item)}
                    className="button"
                  >
                    REMOVE FROM LIST
                  </button>
                  {item.name}
                </li>
              ))}
            </ol>
          ) : (
            <pre>You can purchase items from the stockpile.</pre>
          )}
        </div>
      </div>
      <div className="box">
        <div className="content">
          {state.stockpile.length ? (
            <ol type="1">
              {state.stockpile.map(item => (
                <li key={item.id}>
                  <button onClick={() => addItem(item)} className="button">
                    ADD TO LIST
                  </button>
                  {item.name} (+{item.price})
                </li>
              ))}
            </ol>
          ) : (
            <pre>Nice looking recipe!</pre>
          )}
        </div>

        <div className="content">
          <h4>Total Amount: ${state.recipe.price + state.RecipePrice}</h4>
        </div>
      </div>
    </div>
  );
}
```

If you’re familiar with Redux, you’ll recognize `line 54` in the code sample above where `useReducer` accepts a reducer with the initial state of the component and an action – usually, a dispatch method that is used to update the state of the component as desired. Thus with reducers, we can combine multiple states into one instead of having to create more than one single state Hook. Let’s see how this component works:

{% youtube yLiC3nEM7o0 %}

## Hook collections

Since the release of Hooks, the enthusiasm from the React community has been amazing. Tons of custom Hooks have been created depicting awesome functionalities. Custom React Hook collections you should definitely check out include:

[Collection of React Hooks](https://github.com/nikgraf/react-hooks) which contains more than 300 custom hooks – popular among them is `useArray` – a Hook that provides multiple methods for array manipulation which is a developer’s everyday chore. Let’s update our app to include the `useArray` hook:

```jsx
import React from "react";
import { useArray } from "react-hanger";

const myStyle = {
  color: "white"
};
export default function App() {
  const todos = useArray(["35cl", "50cl", "60cl"]);
  return (
    <div style={myStyle}>
      <h3>Measures</h3>
      <button
        onClick={() =>
          todos.add(Math.floor(Math.random() * (60 - 35 + 1)) + 35 + "cl")
        }
      >
        CUSTOM
      </button>

      <ul>
        {todos.value.map((todo, i) => (
          <div>
            <li key={i}>{todo}</li>
            <button onClick={() => todos.removeIndex(i)}>
              Remove from list
            </button>
          </div>
        ))}
      </ul>
      <button onClick={todos.clear}>clear</button>
    </div>
  );
}
```

Let’s see how that works:

{% youtube dN3BSnw8NgU%}

Another collection I really find interesting is [`useHooks`](https://github.com/gragland/usehooks), which contains `useLockBodyScroll` , a Hook that prevents users from scrolling over a particular component. I observed that this Hook works with React’s inbuilt `useLayoutEffect` Hook – which reads layout from the DOM and re-renders synchronously. To implement `useLockBodyScroll`, you first need to define it as a function:

```jsx
import { useLayoutEffect } from "react";

export default function useLockBodyScroll() {
  useLayoutEffect(() => {
    // Get original value of body overflow
    const originalStyle = window.getComputedStyle(document.body).overflow;
    // Prevent scrolling on mount
    document.body.style.overflow = "hidden";
    // Re-enable scrolling when component unmounts
    return () => (document.body.style.overflow = originalStyle);
  }, []); // Empty array ensures effect is only run on mount and unmount
}
```

Then import it in the desired component:

```jsx
import useLockBodyScroll from "./useLockBodyScroll";

export default function Landing() {
    useLockBodyScroll();
    const [data, setData] = useState([]);
    useEffect(() => {
        fetch(URL)
            .then(response => response.json())
            .then(data => setData(data));
    }, []);
    return ( <
        div >
        <
        button >
        <
        A style = {
            {
                textDecoration: "none"
            }
        }
        href = "/" >
        HOME <
        /A>{" "} <
        br / >
        <
        /button> {
            data.map(item => ( <
                Item.Group key = {
                    item.id
                }
                style = {
                    divStyle
                } >
                <
                Item >
                <
                Item.Image width = "80"
                size = "tiny"
                src = {
                    item.image_url
                }
                alt = "Beer Flask" /
                >
                <
                Item.Content >
                <
                Item.Header > {
                    item.name
                } < /Item.Header> <
                Item.Extra > {
                    item.tagline
                } < /Item.Extra> <
                Item.Meta style = {
                    {
                        lineHeight: 1.5
                    }
                } > {
                    item.description
                } <
                /Item.Meta> <
                /Item.Content> <
                /Item> <
                /Item.Group>
            ))
        } <
        /div>
    );
}
```

Let’s see how that functions. The scrollbar in our browser should be absent:

{%youtube -0SG_EYI-0g%}

There, our app is done for now. Did I forget something you feel is super important? You’re welcome to improve on the demo in CodeSandbox.

{% codesandbox ikfxl %}

## Summary

I think Hooks are the greatest thing to happen to React in a long time. Even though a lot has been achieved so far, there’s still so much we can do. Among React enthusiasts, there [has been the debate in certain forums](https://www.reddit.com/r/reactjs/comments/at1gfz/collection_of_300_react_hooks/) that React providing the facility to create custom Hooks would result in an overload of Hooks in the ecosystem – similar to what occurred with jQuery plugins. What’s your take on Hooks and what awesome Hooks have you discovered recently? Do let me know in the comments below. Cheers.
* * * 
**Editor's note:** Seeing something wrong with this post? You can find the correct version [here](https://blog.logrocket.com/popular-react-hook-libraries/).

## Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps
 
![LogRocket Dashboard Free Trial Banner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png?resize=1200%2C677&ssl=1)
 
[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
[Try it for free](https://logrocket.com/signup/).
* * *
The post [Popular React Hook libraries](https://blog.logrocket.com/popular-react-hook-libraries/) appeared first on [LogRocket Blog](https://blog.logrocket.com).