loading...
Cover image for Top 10 React Hook libraries
Bornfight

Top 10 React Hook libraries

jurajuki profile image Juraj Pavlović Originally published at bornfight.com Updated on ・6 min read

Hooks came and took the React community by the storm. It’s been a while since their initial release, meaning there are a lot of supporting libraries. It is hard not to come by “hooks” word while searching for anything related to React. If you haven’t already, you should pick them up into your codebase as soon as possible. They will make your coding life much easier and enjoyable.

Keeping clean code style, readability, maintainability, fewer lines of code as well as reusability is crucial in the React development. This blog will present to you the top 10 React Hook libraries which you should start using immediately. It is based on personal preference. Without further delay let’s get on the way.

1. use-http

use-http is an incredibly useful package that is used as a replacement for Fetch API. Written and maintained with high quality. It makes your coding much simpler and understandable, more precisely the data consumption part. The hook itself uses TypeScript and even has support for SSR and GraphQL. It returns a response, loading, error data and different request methods such as Get, Post, Put, Patch and Delete.

Main features it provides are:

  • Request/Response interceptors
  • Suspense (experimental currently)
  • Retry functionality
  • Caching

It is well documented with both CodeSandbox examples and Youtube videos together with GitHub readme.

Usage example:

import useFetch from "use-http"

const Example = () => {
  const [todos, setTodos] = useState([])
  const { get, post, response, loading, error } = useFetch("https://example.com")

  useEffect(() => { get("/todos") }, [])

  const addTodo = async () => {
      await post("/todos", { title: "example todo" });
      if (response.ok) setTodos([...todos, newTodo])
  }

  return (
    <>
      <button onClick={addTodo}>Add Todo</button>
      {error && 'Error!'}
      {loading && 'Loading...'}
      {todos.map(todo => (
        <span key={todo.id}>{todo.title}</span>
      )}
    </>
  );
};
Enter fullscreen mode Exit fullscreen mode

2. useMedia

Have you ever needed a way of tracking the CSS media query? The useMedia hook provides a simplistic approach to the problem. It is a sensory hook which tracks exactly that. Media queries are really important as well as the responsiveness of any app or website.

Written in TypeScript it offers its support. The package has well-defined documentation which explains the usage as well as the testing methods for the hook.

Usage example:

import useMedia from 'use-media';

const Example = () => {
  const isWide = useMedia({minWidth: '1000px'});

  return (
    <span>
      Screen is wide: {isWide ? "WideScreen" : "NarrowScreen"}
    </span>
  );
};
Enter fullscreen mode Exit fullscreen mode

3. Constate

Constate is a hook package that provides lifting local state up to React Context. It means that any state from any component can be easily lifted to the context with minimum effort. This is useful in cases where you would like to use the same state in multiple spots, or provide the same state to multiple components. The name comes from a wordplay merging Context and State.
Written in Typescript and very small in size. The documentation is not so detailed, but it gets the job done.

Usage example:

import React, { useState } from "react";
import constate from "constate";

// custom hook
function useCounter() {
  const [count, setCount] = useState(0);
  const increment = () => setCount(prevCount => prevCount + 1);
  return { count, increment };
}

// hook passed in constate
const [CounterProvider, useCounterContext] = constate(useCounter);

function Button() {
  // use the context
  const { increment } = useCounterContext();
  return <button onClick={increment}>+</button>;
}

function Count() {
  // use the context
  const { count } = useCounterContext();
  return <span>{count}</span>;
}

function App() {
  // wrap the component with provider
  return (
    <CounterProvider>
      <Count />
      <Button />
    </CounterProvider>
  );
Enter fullscreen mode Exit fullscreen mode

4. Redux hooks

Redux is a well-known tool for many, if not all, React developers. It is used as a global state manager throughout the application. It went onboard with hooks a couple of months after the React’s initial release. It offers an alternative to the HOC (Higher Order Component) pattern with existing connect() method.

Most notable hooks provided are:

  • useSelector
  • useDispatch
  • useStore

The documentation is quite good, a bit complex but it will provide you with any information needed to start using them.

Usage example:

import {useSelector, useDispatch} from "react-redux";
import React from "react";
import * as actions from "./actions";

const Example = () => {
const dispatch = useDispatch()
const counter = useSelector(state => state.counter)

return (
<div>
   <span>
     {counter.value}
   </span>
   <button onClick={() => dispatch(actions.incrementCounter)}>
     Counter +1
   </button>
</div>
);
};
Enter fullscreen mode Exit fullscreen mode

5. React hook form

React hook form is a form hook library which is similar to Formik and Redux form, but better! With its much simpler syntax, speed, less rerenders and better maintainability it started to climb the GitHub ladders.
It is tiny in size and built with performance in mind. The library offers even its form builder which is great! It has one of the biggest amounts of GitHub starts for a React hooks library, 14.8k.

Usage example:

import React from "react";
import { useForm } from "react-hook-form";

function App() {
  const { register, handleSubmit, errors } = useForm();
  const onSubmit = (data) => {
    // logs {firstName:"exampleFirstName", lastName:"exampleLastName"}
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={register} />
      <input name="lastName" ref={register({ required: true })} />
      {errors.lastName && <span>"Last name is a required field."</span>}
      <input name="age" ref={register({ required: true })} />
      {errors.age && <span>"Please enter number for age."</span>}
      <input type="submit" />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

6. useDebounce

useDebounce represents a small hook which is used for debouncing. It is used to postpone function execution to a later time. Often used in inputs and forms which fetch data.

Usage example:

import React, { useState } from "react";
import { useDebounce } from "use-debounce";

export default function Input() {
  const [text, setText] = useState("Hello");
  const [value] = useDebounce(text, 1000);

  return (
    <div>
      <input
        defaultValue={"Hello"}
        onChange={(e) => {
          setText(e.target.value);
        }}
      />
      <p>Value: {text}</p>
      <p>Debounced value: {value}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

7. useLocalStorage

useLocalStorage is a small hook just like the one above. It is really useful for extracting and setting the data inside localStorage. Manipulation is made easy.
Offers automatic JSON serialization and synchronisation across multiple tabs and is written in TypeScript so it offers types.

Documentation is written in a quality manner and is quite understandable with extended examples.

Usage example:

import React, { useState } from "react";
import { writeStorage } from '@rehooks/local-storage';

export default function Example() {
  let counter = 0;
  const [counterValue] = useLocalStorage('counterValue');

  return (
    <div>
      <span>{counterValue}</span>
      <button onClick={() => writeStorage('i', ++counter)}>
        Click Me
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

8. usePortal

usePortal makes the creation of dropdowns, modals, notification popups, tooltips and much more, super easy! It provides creating elements outside the DOM hierarchy of the App (See how Portals work here).
The hook works with SSR as it is isomorphic. Written in TypeScript and has built-in state. It also offers the full customization of the portal styling and ton of other options.

Documentation written for it is quite good shows many examples which will be more than enough to start using the library/hook yourself.

Usage example:

import React, { useState } from "react";
import usePortal from "react-useportal";

const Example = () => {
    const { ref, openPortal, closePortal, isOpen, Portal } = usePortal()

    return (
      <>
         <button ref={ref} onClick={() => openPortal()}>
            Open Portal
         </button>
          {isOpen && (
            <Portal>
              <p>
                This Portal handles its own state.{' '}
                <button onClick={closePortal}>Close me!</button>, hit ESC or
                click outside of me.
              </p>
            </Portal>
          )}
       </>
 )
}
Enter fullscreen mode Exit fullscreen mode

9. useHover

useHover is a React state hook which determines if a React element is being hovered. Easy and intuitive to use. The library is small, and simple to use, but can be powerful if you’re creative enough.

It offers the delay of the hover effect as well. TypeScript supported. Documentation is not as detailed, but it will show you how to use it fairly.

Usage example:

import useHover from "react-use-hover";

const Example = () => {
  const [isHovering, hoverProps] = useHover();
  return (
    <>
      <span {...hoverProps} aria-describedby="overlay">Hover me</span>
      {isHovering ? <div> Im a little tooltip! </div> : null}
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

10. React router hooks

React router is one of the most popular libraries for React. It is used for routing and getting the app URL history etc. Along with Redux it has implemented its hooks for getting such useful data.

Hooks offered are:

  • useHistory
  • useLocation
  • useParams
  • useRouteMatch

Its names are pretty self-explanatory. UseHistory will get the data of the app’s history and methods such as push which pushes to a new route. UseLocation will return the object that represents the current URL. UseParams will return an object of key-value pairs of URL params of the current route. Finally, useRouteMatch will attempt to match the current URL with the given one which can be a string or an object of different options.

Documentation is good and written with many examples

Usage example:

import { useHistory, useLocation, useRouteMatch } from "react-router-dom";

const Example = () => {
let history = useHistory();
let location = useLoction();
let isMatchingURL = useRouteMatch("/post/11");

function handleClick() {
history.push("/home");
}

return (
    <div>
        <span>Current URL: {location.pathname}</span>
        {isMatchingURL ? <span>Matching provided URL! Yay! </span> : null}
        <button type="button" onClick={handleClick}>
            Go home
        </button>
</div>
);
}
Enter fullscreen mode Exit fullscreen mode

There are much more hook libraries out there, but these are the ones I’ve decided to talk about. Please try them out, I promise you won’t regret it. If you do happen to like them a lot, go and support them in any way. The hooks are still relatively a new way of doing this, but they are here to stay. In further months we expect even more brilliant libraries and hook examples to jump up to the surface.

Hope you have found this post interesting, and that you have learned something new. Have fun in your further exploration of the hooks! Happy developing.

Check out some of my other content!

If you are new to the Hooks world check out this article

If you are interested in learning how to write your custom hooks check this one out

Or perhaps how to start using hooks in a class-based React project, click here

Discussion

pic
Editor guide
Collapse
jfbrennan profile image
Jordan Brennan

This scares me. React codebases are becoming more narrow and isolated from the rest of the web.

useFetch useLocalStorage useForm <--- these especially are bad signs.

How could:

localStorage.setItem('i', ++counter)
Enter fullscreen mode Exit fullscreen mode

not be okay?

How on earth is:

import { writeStorage } from '@rehooks/local-storage';

const [counterValue] = useLocalStorage('counterValue');

writeStorage('i', ++counter)
Enter fullscreen mode Exit fullscreen mode

necessary or even desirable?

Collapse
steventhan profile image
Steven Than

The 2 code snippets are not equivalent. I don't see how the first one re-renders the component for you?

Collapse
jfbrennan profile image
Jordan Brennan

It’s only the diff, everything else in author’s code stays the same.

Thread Thread
steventhan profile image
Steven Than

Well, then you're too quick to dismiss the awesome feature useLocalStorage brings just because the code snippet doesn't fully demonstrate it 🤷

Imagine if you have 10 components on the page that use the same local storage value. I rather import useLocalStorage than reimplement the mechanism to listen for changes

Thread Thread
jfbrennan profile image
Jordan Brennan

So in React you can't just have a simple getter/setter on the state which then calls localStorage.getItem and localStorage.setItem?

Thread Thread
steventhan profile image
Steven Than

Of course you can use those methods on the localStorage object, but then how do you know when to call them so that what's displayed on the screen is in-sync with what's stored?

One can manually attach the onLocalStorageChange event listeners when each component mounts and clean up when they unmount to avoid memory leak. You see this can get tedious, which is why useLocalStorage exists to help: github.com/rehooks/local-storage/b...

I put together a tiny react app here: stackblitz.com/edit/react-5ldn5l. Hopefully, this can highlight some of the features that op left out from the original snippet.

Collapse
jfbrennan profile image
Jordan Brennan

and no diss to you @juraj. Your article is a good read! The React community needs outside help tho! Time for an intervention lol

Collapse
noahlaux profile image
Noah Laux

In terms of state handling in a react functional context, I think the hooks API makes things a lot more simple and easier to encapsulate concepts.

However, I agree with you that this could be considered an anti-pattern. Other state handling libraries (either built-in (think Svelte or Vue in their recent incarnations or standalone) use the concepts of stores (readable/writables), which not only overcome the weird hook dances, like rules about where you have to use and declare hooks, leaving you with state handling as just another primitive.

Collapse
omarkhatibco profile image
Omar Khatib

I would like to suggest another library, I use it on daily basis github.com/streamich/react-use

Collapse
jurajuki profile image
Juraj Pavlović Author

Thank you for sharing!

Collapse
malloc007 profile image
Ryota Murakami

Thanks @jurajuki for this cool post!
Actually I had only knew use-debounce hook, so I got 9 hooks today! 🤣

BTW I have OSS project that also React hook, I like that coincidence!
Here is my library: github.com/laststance/use-app-state

If you have just a little time, I'm really grad to give me feedback your first impression.
I want to know that is this intuitive for many person?

Anyway thanks your hooks knowledge which is really helpful me! 🤗

Collapse
drazik profile image
Cyrille Perois

I would also suggest react-aria that encapsulates logic to add aria attributes for some common cases/components.

Collapse
jurajuki profile image
Juraj Pavlović Author

Another great suggestion! Thank you.

Collapse
almarrr profile image
Almar Groenewald

Thanks. Didn’t know about useDebounce. Don’t need lodash anymore.

Collapse
pharmokan profile image
pharmokan

usehooks.com/ for more hooks over span of 3 years collecting simple drop-ins sans npm

Collapse
samirdamle profile image
Samir Damle

Looks like there’s a bug in the code snippet for use-http in addToDo - the result of await post( ... ) should be captured in response and then newToDo needs to be plucked from the response.

Collapse
olsard profile image
olsard

Great, thanks for sharing!

Collapse
ronca85 profile image
ronca85

i don't want to do this react stuff for any money