UNPKG

hookify-react

Version:

A collection of optimized and reusable React hooks for state management, dom interaction, responsive design, storage, location, asynchronous management and performance improvements.

243 lines (179 loc) • 8.99 kB
# šŸ“¦ hookify-react šŸš€ A collection of **high-performance, reusable, and production-ready React hooks** to simplify state management, DOM interaction, location, async management and browser storage. ![GitHub package.json version](https://img.shields.io/github/package-json/v/uttamakwana/hookify-react) ![npm](https://img.shields.io/npm/dt/hookify-react) ![GitHub stars](https://img.shields.io/github/stars/uttamakwana/hookify-react?style=social) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) ![GitHub issues](https://img.shields.io/github/issues/uttamakwana/hookify-react) ## 🌟 Table of Contents - [Features](#features) - [Installation](#installation) - [Quick Start](#quick-start) - [Available Hooks](#available-hooks) - [API Reference](#api-reference) - [Contributing](#contributing) - [License](#license) - [Contact](#contact) ## <a id="features"></a> šŸš€ Features - āœ… Fully typed with TypeScript - āœ… **SSR-safe** — works with Next.js, Remix and other server-rendered frameworks - āœ… No external dependencies (only `react` as a peer dependency) - āœ… Tree-shakeable ESM + CommonJS builds - āœ… Stable function identities (safe for dependency arrays and memoized children) - āœ… Automatic listener/timer cleanup — no leaks on unmount - āœ… Unit-tested with Vitest + Testing Library --- ## <a id="installation"></a> šŸ“Œ Installation ```sh npm install hookify-react ``` or ```sh yarn add hookify-react ``` > **Peer dependencies:** `react >= 18` and `react-dom >= 18`. ## <a id="quick-start"></a> ⚔ Quick Start ```tsx import { useRef } from "react"; import { useEventListener } from "hookify-react"; export default function Example() { const buttonRef = useRef<HTMLButtonElement>(null); useEventListener("click", () => alert("Button clicked!"), buttonRef); return <button ref={buttonRef}>Click Me</button>; } ``` ## <a id="available-hooks"></a> šŸ” Available Hooks | Category | Hooks | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | **Async Management** | `useDebounce`, `useInterval`, `useTimeout` | | **Effects** | `useAdvancedEffect`, `useUpdatedEffect` | | **DOM Interactions** | `useCopyToClipboard`, `useEventListener`, `useHover`, `useClickOutside`, `useOnlineStatus`, `useOnScreen`, `usePress`, `useScrollInfo` | | **Responsive Design** | `useSize`, `useWindowSize` | | **State Management** | `useArray`, `useCounter`, `useFormState`, `useHistory`, `usePrevious`, `useToggle` | | **Storage** | `useStorage`, `useLocalStorage`, `useSessionStorage` | | **Location** | `useGeoLocation` | ## <a id="api-reference"></a> šŸ“– API Reference ### Async Management ```ts // Runs `callback` once the dependencies have been stable for `delay` ms. useDebounce(callback: () => void, delay: number, deps: unknown[]): void // Auto-starts on mount; pass `null` to pause. Returns a manual stopper. useInterval(callback: () => void, interval?: number | null): { clear: () => void } // Auto-starts on mount. Always uses the latest callback (no need to memoize). useTimeout(callback: () => void, delay: number): { set: () => void; clear: () => void; reset: () => void; } ``` ### Effects ```ts // Like useEffect, but skips the very first render (runs only on updates). useUpdatedEffect(effect: EffectCallback, deps: DependencyList): void // Skips the first render and runs only when deps actually change (Object.is). useAdvancedEffect(effect: EffectCallback, deps: DependencyList): void ``` ### DOM Interactions ```ts // Uses the async Clipboard API with an execCommand fallback for insecure contexts. useCopyToClipboard(resetDelay?: number): { copy: (text: string) => Promise<boolean>; // resolves to `true` on success isCopied: boolean; error: Error | null; } // Defaults to `window`; overloads also accept a Document or HTMLElement ref. useEventListener(eventType, callback, elementRef?, options?): void useHover<T extends HTMLElement>(): { ref: Ref<T>; isHovered: boolean } useClickOutside<T extends HTMLElement>( callback: (event: MouseEvent | TouchEvent) => void, ): { ref: Ref<T> } // Listens to both `online` and `offline`; SSR-safe (assumes online on the server). useOnlineStatus(): { isOnline: boolean; onlineStatus: "online" | "offline" } useOnScreen<T extends HTMLElement>( options?: string | { rootMargin?: string; threshold?: number | number[]; once?: boolean }, ): { ref: Ref<T>; isVisible: boolean } usePress<T extends HTMLElement>(): { ref: Ref<T>; isPressed: boolean } useScrollInfo<T extends HTMLElement>(): { ref: Ref<T>; scrollX: number; scrollY: number; scrollDirection: "up" | "down" | "left" | "right" | "none"; isScrolling: boolean; scrollProgress: number; // 0–100 } ``` ### Responsive Design ```ts useSize<T extends HTMLElement>(): { ref: Ref<T>; size: { width; height; top; left; bottom; right } | null; } useWindowSize(): { width: number; height: number } ``` ### State Management ```ts // `initialValue` defaults to []. All helper methods are referentially stable. useArray<T>(initialValue?: T[]): [T[], SetState<T[]>, { push; pop; shift; unshift; removeByIndex; removeByValue; clear; replace; reset; filter; updateByIndex; updateByValue; }] // Optional { min, max } bounds clamp every update. useCounter(initialValue?: number, options?: { min?: number; max?: number }): { count; increment; incrementByValue; decrement; decrementByValue; set; reset; } useFormState<T>(defaultValue, predicates, options?): [ T, (value: T | ((prev: T) => T)) => void, { errors: string[]; isValid: boolean; status: "idle" | "valid" | "error" }, ] useHistory<T>(defaultValue, options?): [ T, (value: T | ((prev: T) => T)) => void, { history: T[]; pointer: number; back; forward; go }, ] usePrevious<T>(value: T): T | null // Call with no argument to flip, or a boolean to force a value. useToggle(initialValue?: boolean): [boolean, (value?: boolean) => void] ``` ### Storage All storage hooks are SSR-safe and fall back to the default value on the server. `useLocalStorage` additionally syncs across browser tabs via the `storage` event. ```ts useLocalStorage<T>(key: string, defaultValue: T | (() => T)): [T, SetState<T>] useSessionStorage<T>(key: string, defaultValue: T | (() => T)): [T, SetState<T>] useStorage<T>(key: string, defaultValue: T | (() => T), type: "local" | "session"): [T, SetState<T>] ``` ### Location ```ts // Options are read by value, so passing an inline object every render is safe. useGeoLocation(options?: { enableHighAccuracy?: boolean; maximumAge?: number; timeout?: number; retryLimit?: number; retryDelay?: number; }): { loading: boolean; error: { code: number; message: string } | null; coords: GeolocationCoordinates | null } ``` ## āš ļø Migration notes (since `0.0.5`) - **`useCopyToClipboard`** — `error` is now an `Error | null` (previously a `string`). Render `error.message`. `copy()` now resolves to a `boolean`. - **`useOnlineStatus`** — now also exposes `isOnline`. The existing `onlineStatus` field is unchanged. - **`useStorage`** — the third argument is now `"local" | "session"` instead of a `Storage` object. `useLocalStorage`/`useSessionStorage` are unchanged. ## <a id="contributing"></a> šŸ¤ Contributing We welcome contributions! If you have suggestions for improvements or new hooks, please open an issue or submit a pull request. ```sh npm install # install dependencies npm run test # run the Vitest suite npm run lint # run ESLint npm run build # build the package ``` 1. Fork the repository. 2. Create your feature branch (`git checkout -b feature/AmazingFeature`). 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`). 4. Push to the branch (`git push origin feature/AmazingFeature`). 5. Open a pull request. ## <a id="license"></a> šŸ“œ License This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details. ## <a id="contact"></a> šŸ“¬ Contact For any inquiries or support, please reach out to uttamakwana4503@gmail.com. ## Documentation Visit [hookify-react](https://hookify-react.netlify.app) for full documentation.