react-hook-lab
v1.1.0
Published
A lightweight collection of reusable React hooks for async operations, browser APIs, DOM observers, state management, timers, and utilities. Built with TypeScript.
Downloads
530
Maintainers
Keywords
Readme
react-hook-lab
A lightweight collection of reusable React hooks for async work, browser APIs, DOM observers, state helpers, and timers. Written completely in TypeScript.
Table of Contents
Installation
npm install react-hook-labreact is a peer dependency, so install it in your app if it is not already there.
Hooks Overview
| Hook | Category | Description |
| ------------------------- | -------- | --------------------------------------------------------------- |
| useAsync | Async | Resolve promises with state tracking (loading, error, value). |
| useAsyncDebounce | Async | Debounce an asynchronous callback. |
| useDebounce | Async | Delay state updates by a given time. |
| useThrottle | Async | Limit the rate at which a state can update. |
| useClipboard | Browser | Read and write text to the user's clipboard. |
| useLocalStorage | Browser | Persist state in localStorage. |
| useSessionStorage | Browser | Persist state in sessionStorage. |
| useOnlineStatus | Browser | Track the browser's online/offline network status. |
| useClickOutside | DOM | Detect clicks outside a specified element. |
| useElementSize | DOM | Track the width and height of an HTML element. |
| useIntersectionObserver | DOM | Detect visibility of an element on screen. |
| useResizeObserver | DOM | Track an element's dimensions as it resizes. |
| useWidth | DOM | Track the global window inner width. |
| useBoolean | State | Manage a boolean state with specific methods (on, off, toggle). |
| useCounter | State | Manage a numeric counter with min/max bounds. |
| usePrevious | State | Store the previous value of a state or prop. |
| useSharedState | State | Share state seamlessly across components and browser tabs. |
| useToggle | State | Toggle between two generic values. |
| useInterval | Time | Set up a declarative setInterval that cleans up properly. |
| useTimeout | Time | Set up a declarative setTimeout that cleans up properly. |
API Documentation
Async Hooks
useAsync
Execute a promise-returning function and track its loading state, value, and any errors.
import { useAsync } from "react-hook-lab";
function UserProfile({ userId }) {
const { execute, status, value, error } = useAsync(
() => fetch(`/api/users/${userId}`).then((res) => res.json()),
[userId]
);
if (status === "pending") return <div>Loading...</div>;
if (status === "error") return <div>Error: {error.message}</div>;
return <div>{value?.name}</div>;
}useDebounce
Debounce a fast-changing value. The debounced value will only reflect the latest value after the specified delay has passed.
import { useState } from "react";
import { useDebounce } from "react-hook-lab";
function SearchInput() {
const [term, setTerm] = useState("");
const debouncedTerm = useDebounce(term, 500);
// 'debouncedTerm' updates 500ms after the user stops typing
return <input value={term} onChange={(e) => setTerm(e.target.value)} />;
}useThrottle
Throttle a state value so that it updates at most once every specified number of milliseconds.
import { useState } from "react";
import { useThrottle } from "react-hook-lab";
function ScrollTracker() {
const [scroll, setScroll] = useState(0);
const throttledScroll = useThrottle(scroll, 200);
// throttledScroll will update maximally once every 200ms
}useAsyncDebounce
Debounce an asynchronous callback. Useful for preventing spam API calls.
import { useAsyncDebounce } from "react-hook-lab";
function Example() {
const fetchAutocomplete = useAsyncDebounce(async (query) => {
return await api.get(`/search?q=${query}`);
}, 300);
}Browser Hooks
useClipboard
Copy text to the clipboard and temporarily display a copied state.
import { useClipboard } from "react-hook-lab";
function CopyButton() {
const { copy, copied, error } = useClipboard(2000); // Reset 'copied' after 2s
return <button onClick={() => copy("Text to copy!")}>{copied ? "Copied!" : "Copy"}</button>;
}useLocalStorage
Synchronize state with localStorage.
import { useLocalStorage } from "react-hook-lab";
function ThemeToggle() {
const [theme, setTheme] = useLocalStorage("theme", "light");
return <button onClick={() => setTheme("dark")}>Dark Mode</button>;
}useSessionStorage
Synchronize state with sessionStorage.
import { useSessionStorage } from "react-hook-lab";
function FormCache() {
const [name, setName] = useSessionStorage("form-name", "");
return <input value={name} onChange={(e) => setName(e.target.value)} />;
}useOnlineStatus
Detect whether the browser has an active network connection.
import { useOnlineStatus } from "react-hook-lab";
function Status() {
const isOnline = useOnlineStatus();
return <div>{isOnline ? "✅ Online" : "❌ Offline"}</div>;
}DOM Hooks
useClickOutside
Trigger a callback when the user clicks outside a specific DOM element.
import { useRef, useState } from "react";
import { useClickOutside } from "react-hook-lab";
function Dropdown() {
const [isOpen, setIsOpen] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useClickOutside(ref, () => setIsOpen(false));
return (
<div ref={ref}>
<button onClick={() => setIsOpen(true)}>Open Menu</button>
{isOpen && <div>Menu Content</div>}
</div>
);
}useElementSize
Track the height and width of a specific DOM element.
import { useRef } from "react";
import { useElementSize } from "react-hook-lab";
function ResizeBox() {
const ref = useRef<HTMLDivElement>(null);
const { width, height } = useElementSize(ref);
return (
<div ref={ref}>
Size: {width}px x {height}px
</div>
);
}useIntersectionObserver
Track whether a DOM element is currently visible in the viewport.
import { useRef } from "react";
import { useIntersectionObserver } from "react-hook-lab";
function LazyImage() {
const ref = useRef<HTMLImageElement>(null);
const entry = useIntersectionObserver(ref, { threshold: 0.5 });
const isVisible = !!entry?.isIntersecting;
return <img ref={ref} src={isVisible ? "real.jpg" : "placeholder.jpg"} />;
}useResizeObserver
React to changes in a DOM element's dimensions using the native ResizeObserver API.
import { useRef } from "react";
import { useResizeObserver } from "react-hook-lab";
function Resizable() {
const ref = useRef<HTMLDivElement>(null);
const entry = useResizeObserver(ref);
return <div ref={ref}>Width: {entry?.contentRect.width}</div>;
}useWidth
Track the global inner window width.
import { useWidth } from "react-hook-lab";
function View() {
const width = useWidth();
return <div>{width < 768 ? "Mobile" : "Desktop"}</div>;
}State Hooks
useBoolean
Easily manage boolean state with dedicated on, off, and toggle methods.
import { useBoolean } from "react-hook-lab";
function Modal() {
const { value: isOpen, on: open, off: close, toggle } = useBoolean(false);
// ...
}useCounter
Manage numeric state with built-in min and max bounds.
import { useCounter } from "react-hook-lab";
function Cart() {
const [count, { increment, decrement, reset }] = useCounter(1, { min: 1, max: 10 });
return <button onClick={increment}>Add: {count}</button>;
}usePrevious
Access the previous value of a state or prop after a render.
import { useState } from "react";
import { usePrevious } from "react-hook-lab";
function Counter() {
const [count, setCount] = useState(0);
const prevCount = usePrevious(count);
return (
<div>
Now: {count}, Before: {prevCount}
</div>
);
}useSharedState
Share state across different components and synchronize it in real-time across multiple browser tabs using BroadcastChannel. Works exactly like useState.
import { useSharedState } from "react-hook-lab";
function ComponentA() {
const [theme, setTheme] = useSharedState("theme", "light");
return <button onClick={() => setTheme("dark")}>Theme A: {theme}</button>;
}
function ComponentB() {
// Shares the exact same state as ComponentA, even across tabs!
const [theme, setTheme] = useSharedState("theme", "light");
return <button onClick={() => setTheme("light")}>Theme B: {theme}</button>;
}useToggle
Toggle between two values of any type.
import { useToggle } from "react-hook-lab";
function Mode() {
const [mode, toggleMode] = useToggle("light", "dark");
return <button onClick={toggleMode}>Current: {mode}</button>;
}Time Hooks
useInterval
A declarative setInterval hook that handles cleanup and React's closure staleness issues.
import { useState } from "react";
import { useInterval } from "react-hook-lab";
function Clock() {
const [time, setTime] = useState(0);
// Set delay to `null` to pause the interval
useInterval(() => setTime((t) => t + 1), 1000);
}useTimeout
A declarative setTimeout hook.
import { useState } from "react";
import { useTimeout } from "react-hook-lab";
function AutoCloseMessage() {
const [show, setShow] = useState(true);
useTimeout(() => setShow(false), 5000);
if (!show) return null;
return <div>This will disappear in 5 seconds!</div>;
}Browser Compatibility
useClipboard: Relies onnavigator.clipboard. Supported in all modern browsers over HTTPS.useIntersectionObserver: Relies onIntersectionObserver. Supported in all modern browsers.useResizeObserver: Relies onResizeObserver. Supported in all modern browsers.
Polyfills may be required for older browsers like Internet Explorer 11.
