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 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 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 valuesuseBoolean
: Get and set Boolean statesuseNumber
: Get and set number statesuseArray
: Get and set array statesuseOnMount
: Run code when a component mountsuseOnUnmount
: Run code when a component unmountsuseStateful
: Get and set component stateInstall 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.
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.
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 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 synthesisspeak
: Makes the browser start speakingspeaking
: Is a Boolean that tells us whether speech synthesis is in processsupported
: Is a Boolean that informs us whether speech synthesis is supported in the current browservoices
: Has the list of voices to choose frompause
: Lets us pause speakingresume
: Lets us resume speakingReact 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 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:
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, 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 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:
'/'
and '/about'
) return the <HomePage />
and <AboutPage />
components, respectivelyuseRoutes
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<NotFoundPage />
component is rendered, ensuring users are never met with a blank pageuseHooks-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
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.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ 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>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to implement one-way and two-way data binding in Vue.js, using v-model and advanced techniques like defineModel for better apps.
Compare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.