John Au-Yeung I'm a web developer interested in JavaScript stuff.

Comparing the top React Hooks libraries of 2023

12 min read 3527

Comparing The Top React Hooks Libraries Of 2023

Editor’s note: This list of the top React Hook libraries was last updated on 17 July 2023 to add more popular libraries, including React Hook Form, TanStack, React Hook Router, and useHooks-ts.

React’s Hooks API is now the de facto method for creating components. It coexists alongside the class component API, which lets us create components with JavaScript classes. In addition to the standard hooks that come with the React library, developers can create their own hooks. Unsurprisingly, many custom hooks libraries have since been developed to make creating React apps even easier.

In this article, we’ll look at the most popular React Hooks libraries and compare their functionalities. We’ll cover the following:

React Hooks Lib

React Hooks Lib provides us with hooks that resemble the lifecycle methods of React class components. For example, this library offers hooks like useDidMount, which runs when the component is mounted, and useDidUpdate, which runs when the component updates. It also has hooks for managing states, like useCounter, which adds a number state with its own functions to manage it.

To install React Hooks Lib, run the following command:

npm i react-hooks-lib --save

Then, we can use some of the hooks by importing them from the module. To use the useDidMount Hook, write the following code:

import React from "react";
import { useDidMount } from "react-hooks-lib";

export default function App() {
  useDidMount(() => {
    console.log("did mount");
  });

  return (
    <div className="App">
      <h1>Hello world</h1>
    </div>
  );
}

Likewise, we can use the useCounter Hook by writing this:

import React from "react";
import { useCounter } from "react-hooks-lib";

export default function App() {
  const { count, inc, dec, reset } = useCounter(0);
  return (
    <div>
      {count}
      <button onClick={() => inc(1)}>increment</button>
      <button onClick={() => dec(1)}>decrement</button>
      <button onClick={reset}>reset</button>
    </div>
  );
}

This returns an object with the count state and the inc, dec, and reset methods. inc increments count by a given number, dec decrements count by a given number, and reset resets the count to the initial value.

React Hooks Lib also comes with the useField Hook to make getting and setting input values easier. We can use it by writing this:

import React from "react";
import { useField } from "react-hooks-lib";

export default function App() {
  const { value, bind } = useField("text");

  return (
    <div>
      <input type="text" {...bind} />
      <p>{value}</p>
    </div>
  );
}

We just pass the whole bind object into the input, and we can use it to get the data from the input and set it as the value of value. bind also has the value property to set the input value. It also works with select elements:

import React from "react";
import { useField } from "react-hooks-lib";

export default function App() {
  const { value, bind } = useField("text");

  return (
    <div>
      <select {...bind}>
        <option value="apple">apple</option>
        <option value="orange">orange</option>
      </select>
      <p>{value}</p>
    </div>
  );
}

React Hooks Lib comes with many other hooks that provide similar functions. Overall, it provides us with custom hooks that can do a few convenient things. We should note, however, that not all the provided hooks are documented.

react-hanger

react-hanger provides us with React Hooks to more easily manage various kinds of states. It comes with the following hooks:

  • useInput: Get and set input control values
  • useBoolean: Get and set Boolean states
  • useNumber: Get and set number states
  • useArray: Get and set array states
  • useOnMount: Run code when a component mounts
  • useOnUnmount: Run code when a component unmounts
  • useStateful: Get and set component state

Install the package with this command:

npm install react-hanger

We can use useInput as follows to make processing input values simpler:

import React from "react";
import { useInput } from "react-hanger";

export default function App() {
  const input = useInput("");

  return (
    <div>
      <input type="text" value={input.value} onChange={input.onChange} />
      <p>{input.value}</p>
    </div>
  );
}

We can also use useNumber to get and set a number state:

import React from "react";
import { useNumber } from "react-hanger";

export default function App() {
  const counter = useNumber(3, { lowerLimit: 0, upperLimit: 5 });

  return (
    <div>
      <p> {counter.value} </p>
      <button onClick={() => counter.increase()}> increase </button>
      <button onClick={() => counter.decrease()}> decrease </button>
    </div>
  );
}

We can set counter.value‘s initial value with the first argument, and we can set the lower and upper limit of the counter.value state with the second. The useArray and useBoolean Hooks work in a similar way.

To set any kind of state, we can use the useStateful Hook:

import React from "react";
import { useStateful } from "react-hanger";

export default function App() {
  const username = useStateful("tom");

  return (
    <div>
      <p> {username.value} </p>
      <button onClick={() => username.setValue("tom")}> tom </button>
      <button onClick={() => username.setValue("jerry")}> jerry </button>
    </div>
  );
}

This is better than React’s useState Hook because we can get the value of the state from the value property, and we can set the value with the setValue method of the returned object. No destructuring is required to get the state and setter function, unlike React’s built-in useState Hook.

React hookedUp

Like countless other libraries, React hookedUp lets us manage component states. But we can also use it to manage the focus and hovering of HTML elements.

React hookedUp comes with hooks that replicate the functionality of class component lifecycle hooks, as well as a few useful timer and network hooks that aren’t provided by the other libraries we’ve reviewed so far.

Follow this code to install the library:

npm install react-hookedup --save

Let’s take a look at the useHover Hook, which will detect if we hover over an input:

import React from "react";
import { useHover } from "react-hookedup";

export default function App() {
  const { hovered, bind } = useHover();

  return (
    <div>
      <p>{hovered ? "hovered" : "not hovered"}</p>
      <input {...bind} />
    </div>
  );
}

We just spread the whole bind object as props for input. The useFocus Hook can be used in a similar way.

If we miss our good ol’ componentDidMount method in class components, we can use the useOnMount Hook to provide equivalent functionality in function components:

import React from "react";
import { useOnMount } from "react-hookedup";

export default function App() {
  useOnMount(() => console.log("mounted"));
  return <div> hello world </div>;
}

And if we want to call setInterval in our code, we can use the useInterval Hook. For example, we can write:

import React, { useState } from "react";
import { useInterval } from "react-hookedup";

export default function App() {
  const [time, setTime] = useState(new Date().toString());

  useInterval(() => setTime(new Date().toString()), 1000);

  return <p>{time}</p>;
}

We just pass in the callback to run as the first argument and the interval as the second argument, like the setInterval function. It also comes with the useTimeout Hook to run a callback after a given delay:

import React from "react";
import { useTimeout } from "react-hookedup";

export default function App() {
  useTimeout(() => alert("hello world"), 1500);

  return <h1>hello world</h1>;
}

Another useful hook from React hookedUp is useOnlineStatus, which allows us to watch the online status of our app. For example, we can write the following:

import React from "react";
import { useOnlineStatus } from "react-hookedup";

export default function App() {
  const { online } = useOnlineStatus();

  return <h1>{online ? "online" : "offline"}</h1>;
}

This returns the online property, which is true when the device is online. Like we mentioned earlier, React hookedUp also comes with a suite of state management hooks. These work similarly to how they work in the other libraries.

react-use

The react-use hooks library comes with a larger collection of hooks than the other libraries listed so far. It includes hooks to leverage the various hardware that browsers can access. The library also comes with hooks to watch screen size, motion, scrolling, animation, and to dynamically adjust CSS, among other functionalities.

Install react-use with this command:

npm i react-use

For example, we can use the useMouse Hook to watch the position of a user’s mouse:

import React from "react";
import { useMouse } from "react-use";

export default function App() {
  const ref = React.useRef(null);
  const { docX, docY, posX, posY, elX, elY, elW, elH } = useMouse(ref);

  return (
    <div ref={ref}>
      <div>
        Mouse position in document - ({docX}, {docY})
      </div>
      <div>
        Mouse position in element - ({elX}, {elY})
      </div>
      <div>
        Element position- ({posX} , {posY})
      </div>
      <div>
        Element dimensions - {elW}x{elH}
      </div>
    </div>
  );
}

We can use docX and docY to get the x- and y-coordinates of the mouse in the document. We can also use the elX and elY properties to get the x- and y-coordinates of the mouse in the element being monitored. We assign the ref to the element we want to watch.

Similarly, we can use the useScroll Hook to track the scroll position of an element:

import React from "react";
import { useScroll } from "react-use";

export default function App() {
  const scrollRef = React.useRef(null);
  const { x, y } = useScroll(scrollRef);

  return (
    <div ref={scrollRef} style={{ height: 300, overflowY: "scroll" }}>
      <div style={{ position: "fixed" }}>
        <div>x: {x}</div>
        <div>y: {y}</div>
      </div>
      {Array(100)
        .fill()
        .map((_, i) => (
          <p key={i}>{i}</p>
        ))}
    </div>
  );
}

In the code above, we assigned a ref to the element whose scroll position we want to watch, and we set the height and overflowY to scroll so that we can scroll the contents. We get the scroll position with the x and y properties returned. react-use also provides hooks for animation. For example, the useSpring Hook animates number displays:

import React, { useState } from "react";
import useSpring from "react-use/lib/useSpring";

export default function App() {
  const [target, setTarget] = useState(50);
  const value = useSpring(target);

  return (
    <div>
      {value}
      <br />
      <button onClick={() => setTarget(0)}>Set 0</button>
      <button onClick={() => setTarget(200)}>Set 100</button>
    </div>
  );
}

We pass the number to animate to into the useSpring Hook. Then the number will animate until target is reached. Note that rebound is required for this hook to work.



react-use also has hooks to let us commit various side effects, like copying data to the clipboard and manipulating local storage. To add a copy-to-clipboard feature, we can use the useCopyToClipboard Hook:

import React, { useState } from "react";
import useCopyToClipboard from "react-use/lib/useCopyToClipboard";

export default function App() {
  const [text, setText] = useState("");
  const [state, copyToClipboard] = useCopyToClipboard();

  return (
    <div>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <button type="button" onClick={() => copyToClipboard(text)}>
        copy text
      </button>
      {state.error ? (
        <p>error: {state.error.message}</p>
      ) : (
        state.value && <p>Copied {state.value}</p>
      )}
    </div>
  );
}

In the code, we called useCopyToClipboard in our component to get the copyToClipboard function, then we called that to copy whatever is passed in as the argument to the clipboard. Likewise, we can easily work with localStorage via the useLocalStorage Hook:

import React from "react";
import useLocalStorage from "react-use/lib/useLocalStorage";

export default function App() {
  const [value, setValue, remove] = useLocalStorage("key", "foo");

  return (
    <div>
      <div>Value: {value}</div>
      <button onClick={() => setValue("bar")}>bar</button>
      <button onClick={() => setValue("baz")}>baz</button>
      <button onClick={() => remove()}>Remove</button>
    </div>
  );
}

value has the value of the localStorage entry with the given key, setValue lets us pass in the value to set, and remove removes the entry from local storage.

In addition to the aforementioned hooks, which are unique to react-use, the library comes with many hooks for setting states, using browser APIs, running async code, and much more. react-use is by far the most comprehensive hooks library we’ve looked at so far.

React Recipes

React Recipes is another hooks library that comes with great custom hooks. It offers many of the same hooks as react-use, including those that use browser APIs, manage states, run async code, etc.

To install React Recipes, run the following command:

npm i react-recipes --save

For example, we can use the useSpeechSynthesis Hook to make the browser speak:

import React, { useState } from "react";
import { useSpeechSynthesis } from "react-recipes";

export default function App() {
  const [value, setValue] = useState("");
  const [ended, setEnded] = useState(false);
  const onBoundary = (event) => {
    console.log(`${event.name}: ${event.elapsedTime} milliseconds.`);
  };
  const onEnd = () => setEnded(true);
  const onError = (event) => {
    console.warn(event);
  };

  const {
    cancel,
    speak,
    speaking,
    supported,
    voices,
    pause,
    resume
  } = useSpeechSynthesis({
    onEnd,
    onBoundary,
    onError
  });

  if (!supported) {
    return "Speech is not supported.";
  }

  return (
    <div>
      <input value={value} onChange={(event) => setValue(event.target.value)} />
      <button
        type="button"
        onClick={() => speak({ text: value, voice: voices[1] })}
      >
        Speak
      </button>
      <button type="button" onClick={cancel}>
        Cancel
      </button>
      <button type="button" onClick={pause}>
        Pause
      </button>
      <button type="button" onClick={resume}>
        Resume
      </button>
      <p>{speaking && "Voice is speaking"}</p>
      <p>{ended && "Voice has ended"}</p>
      <div>
        <h2>Voices:</h2>
        <div>
          {voices.map((voice) => (
            <p key={voice.name}>{voice.name}</p>
          ))}
        </div>
      </div>
    </div>
  );
}

With React Recipes, we can call the useSpeechSynthesis Hook, which returns an object with various properties:

  • cancel: Cancels the speech synthesis
  • speak: Makes the browser start speaking
  • speaking: Is a Boolean that tells us whether speech synthesis is in process
  • supported: Is a Boolean that informs us whether speech synthesis is supported in the current browser
  • voices: Has the list of voices to choose from
  • pause: Lets us pause speaking
  • resume: Lets us resume speaking

React Recipes comes with many hooks, which provide us with great functionality that isn’t provided by React itself out of the box. It’s also worth nothing that React Recipe is a truly well-documented and comprehensive library.

React Hook Form

React Hook Form is a performant and flexible library for React that simplifies form validation and data gathering. It is built upon the idea of leveraging uncontrolled components and the native HTML form validation. Uncontrolled components in React are those that store their own state internally and you query the DOM using a ref to find its current value when needed, as opposed to controlled components, which have their state controlled by React.

Advantages:

  1. Performance: By not re-rendering the component on every state update, React Hook Form improves the performance, especially with large forms
  2. Integration with native form validation: React Hook Form makes use of the built-in form validation rules, offering a balance between validation and customizability
  3. Flexibility: With the API it provides, it’s easier to integrate with other libraries and build complex validation rules

To install this library, run the following command:

npm install react-hook-form

Here’s an example of how you can use it:

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

export default function App() {
  const { register, handleSubmit } = useForm({
    shouldUseNativeValidation: true,
  });
  const onSubmit = (data) => console.log(data);
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        {...register("firstName", {
          required: "Please enter your first name.",
        })} // custom message
      />
      <input type="submit" />
    </form>
  );
}

In this example, the useForm function is a primary hook from the React Hook Form library that gives access to various form-related methods. The register function is used to connect and validate input fields. You apply this function to your input fields so that they can be recognized and validated by React Hook Form. The handleSubmit function is employed to handle the form’s submission process. It ensures that the form’s data is validated according to the rules you’ve defined before the actual submission function (onSubmit) is invoked.

Inside the onSubmit function, you’d typically send the form data to an API or handle it as per your application’s requirements. In this provided code, it merely logs the validated data to the console. The form’s input for "firstName" is required, and in case this requirement isn’t met, a custom error message: "Please enter your first name", is displayed.

TanStack

TanStack, formerly React Query, is a robust library for fetching, caching, synchronizing, and updating server state in React applications. This library provides hooks like useQuery, useQueryClient, QueryClient, QueryClientProvider, and useMutation that allow you to fetch and mutate data with ease.

To install the package, run the following command:

npm install react-query

Here’s a basic usage example:

import {
  useQuery,
  useMutation,
  useQueryClient,
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'
import { getUsers, postUser } from '../my-api'

// Create a client
const queryClient = new QueryClient()

export default function App() {
  return (
    // Provide the client to your App
    <QueryClientProvider client={queryClient}>
      <Users />
    </QueryClientProvider>
  )
}

function Users() {
  // Access the client
  const queryClient = useQueryClient()
  // Queries
  const query = useQuery({ queryKey: ['users'], queryFn: getUsers })
  // Mutations
  const mutation = useMutation({
    mutationFn: postUser,
    onSuccess: () => {
      // Invalidate and refetch
      queryClient.invalidateQueries({ queryKey: ['users'] })
    },
  })

  return (
    <div>
      <ul>
        {query.data?.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
      <button
        onClick={() => {
          mutation.mutate({
            id: Date.now(),
            name: 'John Doe',
          })
        }}
      >
        Add User
      </button>
    </div>
  )
}

In this example, getUsers and postUser are functions that handle getting and posting data to your API. You would replace these with your actual API calls. The useQuery Hook is used to fetch users from your API, and the useMutation Hook is used to add a new user. When a new user is added successfully, the onSuccess function invalidates the 'users' query, causing React Query to automatically refetch the users from your API.

React Hook Router

React Hook Router is a modern, hook-based routing solution for React. It is highly customizable and requires no external dependencies apart from React itself. It offers a refreshing take on routing in React. Relying on hooks, it sheds the overhead of complex configurations and external dependencies. This means a more streamlined, intuitive, and lightweight approach to managing routes in React applications.

To install React Hook Router, you can run:

npm install hookrouter

Here’s an example of how you can use it:

import React from 'react';
import { useRoutes } from 'hookrouter';

const routes = {
  '/': () => <HomePage />,
  '/about': () => <AboutPage />,
};

export default function App() {
  const routeResult = useRoutes(routes);

  return routeResult || <NotFoundPage />;
}

In the presented code, we have the following:

  1. Routing definition: Routes are defined as a simple JavaScript object. Each key represents a path, and its corresponding value is a function returning a React component. Here, two routes ('/' and '/about') return the <HomePage /> and <AboutPage /> components, respectively
  2. Usage: The useRoutes Hook is central to the routing mechanism. It accepts the defined routes and determines which component to render based on the current URL. The routeResult contains the matched component or remains undefined if no route matches
  3. Fallback rendering: If no route matches the current URL, a fallback <NotFoundPage /> component is rendered, ensuring users are never met with a blank page

useHooks-ts

useHooks-ts is a collection of reusable React hooks with TypeScript support. It extends React’s standard hooks with enhanced functionality and introduces additional hooks not found in the base library. A notable hook in this library is useAsync, which simplifies handling asynchronous functions in components. Here is an example of its usage:

import React from 'react';
import { useAsync } from 'usehooks-ts';

function MyComponent() {
  const { execute, value, loading, error } = useAsync(fetchData, false);

  return (
    <div>
      {loading ? (
        "Loading..."
      ) : error ? (
        `Error: ${error}`
      ) : (
        `Fetched Data: ${JSON.stringify(value)}`
      )}
      <button onClick={execute} disabled={loading}>
        Fetch Data
      </button>
    </div>
  );
}

async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  if (!response.ok) throw new Error('Error fetching data');
  return response.json();
}

You can install the library with the command:

npm install usehooks-ts

Conclusion

By far the most comprehensive and useful React Hooks libraries we reviewed today are react-use and React Recipes. They provide us with hooks for a variety of use cases so that we don’t have to write them from scratch. Some other honorable mentions are React Hook Form, which is excellent for managing form inputs and validation, and TanStack’s React Query, which offers hooks for managing asynchronous data fetches.

React Hooks Lib, react-hanger, and React hookedUp provide basic hooks for state management that can help us simplify state management to a certain extent. If that’s all we’re looking for out of a hooks library, then these libraries are useful. They are all easy to use, and most of them are clearly documented.


More great articles from LogRocket:


Get set up with LogRocket's modern React error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to get an app ID.
  2. Install LogRocket via NPM or script tag. LogRocket.init() must be called client-side, not server-side.
  3. $ npm i --save logrocket 

    // Code:

    import LogRocket from 'logrocket';
    LogRocket.init('app/id');
    Add to your HTML:

    <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
  4. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • ngrx middleware
    • Vuex plugin
Get started now
John Au-Yeung I'm a web developer interested in JavaScript stuff.

Leave a Reply