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.
757 lines (731 loc) • 26.5 kB
text/typescript
import React$1, { EffectCallback, DependencyList, Dispatch, SetStateAction } from 'react';
type TUseAdvancedEffectReturn = void;
/**
* A custom React hook that enhances `useEffect` with advanced dependency comparison.
*
* - It **skips execution on the initial render**.
* - It **executes the effect only if the dependencies change** between renders.
* - It prevents unnecessary re-executions when dependencies remain unchanged.
*
* @param {EffectCallback} effect - The effect function to execute.
* @param {DependencyList} deps - An array of dependencies that determine when the effect runs.
*
* @example
* import { useAdvancedEffect } from "hookify-react";
* import { useState } from "react";
* export default function UseAdvancedEffectExample() {
* const [count, setCount] = useState(0);
* const [otherCount, setOtherCount] = useState(0);
*
* useAdvancedEffect(() => {
* console.log("Effect triggered:", count);
* }, [count]);
*
* return (
* <div style={{ textAlign: "center", fontFamily: "Arial, sans-serif" }}>
* <h2>useAdvancedEffect Hook Example</h2>
* <p>Count: <strong>{count}</strong></p>
* <p>Other count: <strong>{otherCount}</strong></p>
* <button onClick={() => setCount(prev => prev + 1)}>Increment</button>
* <button onClick={() => setOtherCount(prev => prev + 1)}>
* Increment other count
* </button>
* <p>Check the console for effect triggers.</p>
* </div>
* );
* }
*/
declare function useAdvancedEffect(effect: EffectCallback, deps: DependencyList): TUseAdvancedEffectReturn;
type TUseUpdatedEffectReturn = void;
/**
* A custom hook that only executes the effect when dependencies change.
*
* @param {EffectCallback} effect - The effect function to execute.
* @param {DependencyList} deps - An array of dependencies to track changes.
*
* @example
* import { useUpdatedEffect } from "hookify-react";
*
* export default function useUpdatedEffect() {
* useUpdatedEffect(() => {
* console.log("Effect triggered due to dependency change.");
* }, [someState]);
*
* return <div>Check the console!</div>;
* }
*/
declare function useUpdatedEffect(effect: EffectCallback, deps: DependencyList): TUseUpdatedEffectReturn;
type TUseArrayMethods<T> = {
push: (value: T) => number;
pop: () => T | undefined;
shift: () => T | undefined;
unshift: (value: T) => number;
removeByIndex: (index: number) => void;
removeByValue: (value: T) => void;
clear: () => void;
replace: (newArray: T[]) => void;
reset: () => void;
filter: (predicate: (value: T, index: number, array: T[]) => boolean) => void;
updateByIndex: (index: number, value: T) => void;
updateByValue: (prevValue: T, newValue: T) => void;
};
type TUseArrayReturn<T> = readonly [
T[],
Dispatch<SetStateAction<T[]>>,
TUseArrayMethods<T>
];
/**
* A custom React hook for managing arrays. It provides utility functions for common operations
* like adding, removing, updating, and resetting array elements.
*
* @template T - The type of elements in the array.
* @param initialValue - The initial value of the array.
* @returns An array containing the state, setState and utility functions to manipulate it.
* - `push`: Adds a value to the end of the array.
* - `pop`: Removes and returns the last element of the array.
* - `unshift`: Adds a value to the beginning of the array.
* - `shift`: Removes and returns the first element of the array.
* - `removeByIndex`: Removes the first occurrence of a specified index from the array.
* - `removeByValue`: Removes the first occurrence of a specified value from the array.
* - `clear`: Clears all elements from the array.
* - `replace`: Replaces the current array with a new array.
* - `reset`: Resets the array to its initial value.
* - `filter`: Filters the array based on a predicate function and updates the state.
* - `updateByIndex`: Updates the value of an element at a specific index.
* - `updateByValue`: Updates the first occurrence of a specific value with a new value.
*
* @example
* import { useArray } from "hookify-react";
*
* export default function UseArray() {
* const [data, setData, { push, pop, clear, filter }] = useArray<{ name: string, age: number }>();
*
* return <div>Render and perform the action over here</div>
* }
*/
declare function useArray<T>(initialValue: T[]): TUseArrayReturn<T>;
type CounterValueType = number;
/**
* A custom hook that provides functionality for managing a counter.
* It allows for incrementing, decrementing, and resetting the counter,
* as well as incrementing and decrementing by a specific value.
*
* @param initialValue - The initial value of the counter.
*
* @returns An object containing the following:
* - `count`: The current value of the counter.
* - `increment`: Function to increment the counter by 1.
* - `incrementByValue`: Function to increment the counter by a specified value.
* - `decrement`: Function to decrement the counter by 1.
* - `decrementByValue`: Function to decrement the counter by a specified value.
* - `reset`: Function to reset the counter to its initial value.
*
* @example
* import { useCounter } from "hookify-react";
*
* export default function UseCounter() {
* const { count, increment, decrement } = useCounter(0);
*
* return (
* <div>
* <button onClick={increment}>+1</button>
* <button onClick={decrement}>-1</button>
* </div>
* );
* }
*/
declare function useCounter(initialValue?: CounterValueType): {
count: number;
increment: () => void;
incrementByValue: (value: CounterValueType) => void;
decrement: () => void;
decrementByValue: (value: CounterValueType) => void;
reset: () => void;
};
type TError = string | undefined;
type TDefaultValue<T> = T | (() => T);
type TPredicates<T> = Array<(value: T) => TError>;
type TOptions = {
emptyInputValidation?: boolean;
};
type TStatus = "idle" | "valid" | "error";
type TData = {
errors: Array<string>;
isValid: boolean;
status: TStatus;
};
type TUseFormStateReturn<T> = readonly [T, Dispatch<SetStateAction<T>>, TData];
/**
* Custom hook to manage form state with validation and error tracking.
* @template T - Type of the form state value.
* @param {TDefaultValue<T>} defaultValue - Initial value or a function returning the initial value.
* @param {TPredicates<T>} predicates - Array of validation functions returning an error message or undefined.
* @param {TOptions} [options] - Additional configuration options.
* @returns {[T, (value: T | TSetterFunction<T>) => void, { errors: string[], isValid: boolean, status: "idle" | "valid" | "error" }]}
* Returns the state, a setter function, and an object containing validation errors, validity status, and form status.
*
* @example
* import { useFormState } from "hookify-react";
*
* export default function UseFormState() {
* const [name, setName, { errors, isValid, status }] = useFormState("Hooks for React", [(name) => name.length < 3 ? "Name must have atleast 3 character" : undefined, (name) => name.includes("bad words") ? "Name must not contain bad words" ? undefined]);
*
* return (
* <div>
* <input value={name} onChange={e => setName(e.target.value)} placeholder="Enter your name" />
* </div>
* );
* }
*/
declare function useFormState<T>(defaultValue: TDefaultValue<T>, predicates: TPredicates<T>, { emptyInputValidation }?: TOptions): TUseFormStateReturn<T>;
type TUseHistoryOptions = {
capacity?: number;
};
type TUseHistoryReturn<T> = readonly [
T,
(value: T | ((prev: T) => T)) => void,
{
history: T[];
pointer: number;
back: () => void;
forward: () => void;
go: (index: number) => void;
}
];
/**
* Custom hook to manage state with history tracking, supporting undo/redo functionality.
*
* @template T - The type of the state value.
* @param {T | (() => T)} defaultValue - Initial state value or a function returning the initial value.
* @param {TUseHistoryOptions} [options] - Configuration options for history tracking.
* @returns {[T, (value: T | ((prev: T) => T)) => void, { history: T[], pointer: number, back: () => void, forward: () => void, go: (index: number) => void }]}
* Returns the current state, a setter function, and an object containing history, pointer, and navigation functions.
*
* @example
* import { useHistory } from "hookify-react";
*
* export default function UseHistory() {
* const [value, setValue, { history, pointer, forward, go, back }] = useHistory([0]);
*
* return <div>Play with the value</div>;
* }
*/
declare function useHistory<T>(defaultValue: T | (() => T), { capacity }?: TUseHistoryOptions): TUseHistoryReturn<T>;
/**
* Custom React hook to store and retrieve the previous value of a given state or prop.
*
* @template T - The type of the tracked value.
* @param value - The current value to track.
* @returns The previous value before the last update, or `null` if no previous value exists.
*
* @example
* import { useState } from "react";
* import { usePrevious } from "hookify-react";
*
* export default function UsePreviousExample() {
* const [count, setCount] = useState(0);
* const prevCount = usePrevious(count);
*
* console.log(`Previous count: ${prevCount}, Current count: ${count}`);
*
* return (
* <div>
* <button onClick={() => setCount(prev => prev + 1)}>+1</button>
* <p>Current count value: <strong>{count}</strong></p>
* <p>Previous count value: <strong>{prevCount}</strong></p>
* </div>
* );
* }
*/
declare function usePrevious<T>(value: T): T | null;
type TUseToggleReturn = readonly [boolean, (value?: boolean) => void];
/**
* A custom React hook that manages a boolean state and provides a function to toggle it and make it true or false whenever needed.
*
* @param initialValue - The initial value of the boolean state.
* @returns An array containing the current state and a function to toggle it.
*
* @example
* import { useToggle } from 'hookify-react';
*
* export default function UseToggleExample() {
* const [isToggled, toggle] = useToggle(false);
*
* return (
* <div>
* <button onClick={toggle}>Toggle</button>
* <button onClick={() => toggle(true)}>Toggle to true</button>
* <button onClick={() => toggle(false)}>Toggle to false</button>
* <p>Toggle is: {isToggled ? 'On' : 'Off'}</p>
* </div>
* );
* }
*
*/
declare function useToggle(initialValue: boolean): TUseToggleReturn;
/**
* Custom hook that delays the execution of a callback function
* until after a specified delay has elapsed since the last change in dependencies.
*
* @param {() => void} callback - The function to debounce.
* @param {number} delay - The delay in milliseconds before executing the callback.
* @param {unknown[]} deps - The dependencies that trigger the debounce effect.
*
* @example
* // Usage example in a component:
* function SearchComponent() {
* const [query, setQuery] = useState("");
*
* useDebounce(() => {
* console.log("Searching for:", query);
* }, 500, [query]);
*
* return (
* <input
* type="text"
* placeholder="Search..."
* value={query}
* onChange={(e) => setQuery(e.target.value)}
* />
* );
* }
*/
declare function useDebounce(callback: () => void, delay: number, deps: unknown[]): void;
/**
* Custom hook for managing a timeout.
*
* @param {() => void} callback - The function to execute when the timeout completes.
* @param {number} delay - The delay in milliseconds for the timeout.
* @returns {{ set: () => void, clear: () => void, reset: () => void }} - Functions to control the timeout.
*
* @example
* // Example usage in a component:
* function ExampleComponent() {
* const { set, clear, reset } = useTimeout(() => {
* console.log("Timeout executed!");
* }, 1000);
*
* return (
* <div>
* <button onClick={set}>Start Timeout</button>
* <button onClick={clear}>Clear Timeout</button>
* <button onClick={reset}>Reset Timeout</button>
* </div>
* );
* }
*/
declare function useTimeout(callback: () => void, delay: number): {
set: () => void;
clear: () => void;
reset: () => void;
};
/**
* A custom hook to execute a callback at a specified interval.
*
* @param {() => void} callback - The function to execute at each interval.
* @param {number} [interval=1000] - The time in milliseconds between executions (defaults to 1000ms).
* @returns {{ clear: () => void }} - A function to stop the interval.
*
* @example
* import { useState } from "react";
* import { useInterval } from "hookify-react";
*
* export default function UseIntervalExample() {
* const [count, setCount] = useState(0);
* const { clear } = useInterval(() => setCount((prev) => prev + 1), 1000);
*
* return (
* <div>
* <p>Counter: {count}</p>
* <button onClick={clear}>Stop Timer</button>
* </div>
* );
* }
*/
declare function useInterval(callback: () => void, interval?: number): {
clear: () => void;
};
type TUseStorageReturn<T> = readonly [T, Dispatch<SetStateAction<T>>];
/**
* Custom hook to synchronize state with localStorage or sessionStorage.
*
* @template T - The type of the stored value.
* @param key - The storage key.
* @param defaultValue - The default value or a function returning the default value.
* @param storage - The Storage object (localStorage or sessionStorage).
* @returns A tuple containing the stored value and a setter function.
*
* @example
* const [data, setData] = useLocalStorage("user", { name: "John" });
* setData({ name: "Doe" }); // Updates localStorage and state
*/
declare function useStorage<T>(key: string, defaultValue: T | (() => T), storage: Storage): TUseStorageReturn<T>;
/**
* Hook for syncing state with `localStorage`.
* @template T - The type of the stored value.
* @param key - The storage key.
* @param defaultValue - The default value or a function returning the default value.
*
* @example
* import { useLocalStorage } from "hookify-react";
*
* export default function UseLocalStorage() {
* const [name, setName] = useLocalStorage("name", "default name");
*
* return <p>Your name is {name}</p>
* }
*/
declare function useLocalStorage<T>(key: string, defaultValue: T): TUseStorageReturn<T>;
/**
* Hook for syncing state with `sessionStorage`.
* @template T - The type of the stored value.
* @param key - The storage key.
* @param defaultValue - The default value or a function returning the default value.
*
* @example
* import { useSessionStorage } from "hookify-react";
*
* export default function UseSessionStorage() {
* const [name, setName] = useSessionStorage("name", "default name");
*
* return <p>Your name is {name}</p>
* }
*/
declare function useSessionStorage<T>(key: string, defaultValue: T): TUseStorageReturn<T>;
type TUseCopyToClipboardReturn = {
copy: (text: string) => Promise<void>;
isCopied: boolean;
error: string | null;
};
/**
* A custom React hook to copy text to the clipboard.
*
* - Uses the modern `navigator.clipboard` API.
* - Provides feedback on copy success or failure.
* - Ensures clipboard API availability.
*
* @returns {Object} An object containing:
* - `copy`: A function to copy text to the clipboard.
* - `isCopied`: Boolean indicating whether copying was successful.
* - `error`: Any error that occurred while copying.
*
* @example
* import { useCopyToClipboard } from "hookify-react";
*
* export default function UseCopyToClipboard() {
* const { copy, isCopied, error } = useCopyToClipboard();
*
* return (
* <div>
* <button onClick={() => copy("Hello, Clipboard!")}>Copy</button>
* {isCopied && <span>Copied successfully!</span>}
* {error && <span>Error copying: {error}</span>}
* </div>
* );
* }
*/
declare function useCopyToClipboard(): TUseCopyToClipboardReturn;
/**
* A custom hook for adding event listeners to elements efficiently.
*
* @param eventType - The type of event to listen for (e.g., 'click', 'keydown').
* @param callback - The function to execute when the event fires.
* @param elementRef - A React ref pointing to the target element (defaults to `window`).
* @param options - Additional options for `addEventListener`.
*
* @example
* import { useEventListener } from "hookify-react";
*
* export default function UseEventListener() {
* const buttonRef = useRef<HTMLButtonElement>(null);
*
* useEventListener("click", () => alert("Button clicked!"), buttonRef);
*
* return <button ref={buttonRef}>Click Me</button>;
* }
*/
declare function useEventListener<K extends keyof WindowEventMap>(eventType: K, callback: (event: WindowEventMap[K]) => void, elementRef?: React.RefObject<HTMLElement | Window | Document>, options?: boolean | AddEventListenerOptions): void;
type TUseHoverReturn<T> = {
ref: React.MutableRefObject<T | null>;
isHovered: boolean;
};
/**
* A custom hook to track hover state on an element.
*
* @returns {Object} An object containing:
* - `ref`: A ref that you can attach to any element
* - `isHovered`: Boolean indicating an element is being hovered or not
*
* @example
* import { useHover } from "hookify-react";
*
* export default function UseHoverExample() {
* const { ref, isHovered } = useHover();
*
* return (
* <div
* ref={ref}
* style={{
* width: "200px",
* height: "100px",
* display: "flex",
* alignItems: "center",
* justifyContent: "center",
* background: isHovered ? "blue" : "gray",
* color: "white",
* fontSize: "18px",
* borderRadius: "8px",
* transition: "background 0.3s ease",
* }}
* >
* {isHovered ? "Hovered! 🎯" : "Hover over me!"}
* </div>
* );
* }
*/
declare function useHover<T extends HTMLElement>(): TUseHoverReturn<T>;
type TUseClickOutsideReturn<T> = {
ref: React.MutableRefObject<T | null>;
};
/**
* A custom React hook that listens for clicks outside of a specified element and triggers a callback function.
*
* @param elementRef - A React ref object pointing to the target element.
* @param callback - A function to be executed when a click occurs outside the element.
*
* @return {Object} An object containing:
* - `ref`: A ref that you can attach to any element
*
* @example
* import { useClickOutside } from "hookify-react";
* import { useState } from "react";
*
* export default function ClickOutsideExample() {
* const [isOpen, setIsOpen] = useState(true);
* const { ref } = useClickOutside<HTMLDivElement>(() => setIsOpen(false));
*
* return (
* <div>
* <button onClick={() => setIsOpen(true)}>Open Modal</button>
* {isOpen && (
* <div ref={ref} style={{ padding: "20px", border: "1px solid black", width: "200px" }}>
* Click outside of this box to close it.
* </div>
* )}
* </div>
* );
* }
*/
declare function useClickOutside<T extends HTMLElement>(callback: () => void): TUseClickOutsideReturn<T>;
type TOnlineStatus = "online" | "offline";
type TUseOnlineStatusReturn = {
onlineStatus: TOnlineStatus;
};
/**
* A custom hook that tracks the online/offline status of the user's network connection.
*
* @returns {Object} An object containing:
* - `onlineStatus`: Indicating whether the user is "online" or "offline".
*
* @example
* import { useOnlineStatus } from "hookify-react";
*
* export default function UseOnlineStatusExample() {
* const { onlineStatus } = useOnlineStatus();
*
* return (
* <div>
* {onlineStatus === "online" ? "You are online 😁" : "You are offline 😥"}
* </div>
* );
* }
*/
declare function useOnlineStatus(): TUseOnlineStatusReturn;
type TUseOnScreenReturn<T> = {
ref: React.MutableRefObject<T | null>;
isVisible: boolean;
};
/**
* Custom hook to check if an element is visible within the viewport.
*
* @param element - A React ref object pointing to the target element.
* @param rootMargin - Margin around the root. Can have values similar to CSS margin properties.
* @returns `true` if the element is visible on the screen, otherwise `false`.
*
* @example
* import { useOnScreen } from "hookify-react";
*
* export default function UseOnScreenExample() {
* const { ref, isVisible } = useOnScreen("-100px");
*
* return (
* <div>
* <div style={{ height: "100svh" }}>Scroll down to see the box</div>
* <div
* ref={ref}
* style={{
* height: "400px",
* backgroundColor: isVisible ? "lightgreen" : "lightcoral",
* display: "flex",
* alignItems: "center",
* justifyContent: "center",
* fontSize: "20px",
* }}
* >
* {isVisible ? "I'm visible! 🎉" : "Not in view 👀"}
* </div>
* </div>
* );
* }
*/
declare function useOnScreen<T extends HTMLElement>(rootMargin?: string): TUseOnScreenReturn<T>;
type TUsePressReturn<T> = {
ref: React$1.MutableRefObject<T | null>;
isPressed: boolean;
};
/**
* Custom hook to check if an element is being pressed or not
*
* @returns {Object} An object containing:
* - `ref`: A ref that you can attach to any element
* - `isPressed`: Boolean indicating whether an element is being pressed or not
*
* @example
* import { usePress } from "hookify-react";
*
* export default function UsePressExample() {
* const { ref, isPressed } = usePress<HTMLButtonElement>();
*
* return (
* <button ref={ref} style={{ padding: "10px", fontSize: "16px" }}>
* {isPressed ? "Wow that feels good! 😁" : "Please press me! 😥"}
* </button>
* );
* }
*/
declare function usePress<T extends HTMLElement>(): TUsePressReturn<T>;
type ScrollDirection = "up" | "down" | "left" | "right" | "none";
type ScrollInfo = {
scrollX: number;
scrollY: number;
scrollDirection: ScrollDirection;
isScrolling: boolean;
scrollProgress: number;
};
type TUseScrollInfoReturn<T> = {
ref: React.MutableRefObject<T | null>;
} & ScrollInfo;
/**
* Custom hook to track scroll position, direction, and activity.
*
* @param {HTMLElement | null} targetElement - Optional element to track, defaults to window.
* @returns {Object} - An object containing:
* - `ref`: A ref that you can attach to any element
* - `scrollX`: Horizontal scroll position
* - `scrollY`: Vertical scroll position
* - `scrollDirection`: A scroll direction (up, down, left, right, none)
* - `isScrolling`: Boolean indicating whether an element is being scrolled or not
* - `scrollProgress`: Percentage value of how much an element is scrolled
*
* @example
* import { useScrollInfo } from "hookify-react";
*
* export default function UseScrollInfo() {
* const { ref, scrollX, scrollY, scrollDirection, isScrolling, scrollProgress } = useScrollInfo<HTMLDivElement>();
*
* return <div ref={ref}>Get the scroll info of this div</div>
* }
*/
declare function useScrollInfo<T extends HTMLElement>(): TUseScrollInfoReturn<T>;
type TSize = {
width: number;
height: number;
top: number;
left: number;
bottom: number;
right: number;
};
type TUseSizeReturn<T> = {
ref: React.MutableRefObject<T | null>;
size: TSize | null;
};
/**
* Custom hook to track the size of an HTML element in real-time.
*
* @template T - The HTMLElement type.
* @returns {Object} An object containing:
* - `ref`: A ref to attach to the target element.
* - `size`: The element's current size (`width`, `height`, `top`, `left`, `bottom`, `right`).
*
* @example
* import { useSize } from "hookify-react";
*
* export default function UseSize() {
* const { ref, size } = useSize<HTMLDivElement>();
*
* return <div ref={ref}>Get size of this element</div>
* }
* ```
*/
declare function useSize<T extends HTMLElement>(): TUseSizeReturn<T>;
type WindowSize = {
width: number;
height: number;
};
type TUseWindowSizeReturn = WindowSize;
/**
* Custom hook to track the size of the browser window in real-time.
*
* @returns {Object} An object containing:
* - `width`: The current width of the window.
* - `height`: The current height of the window.
*
* @example
* import { useWindowSize } from "hookify-react";
*
* export default function UseWindowSize() {
* const { width, height } = useWindowSize();
* console.log(`Window Size: ${width} x ${height}`);
*
* return <div>Get a window size</div>
* }
*/
declare function useWindowSize(): TUseWindowSizeReturn;
type TPositionError = {
code: number;
message: string;
};
type TUseLocationReturn = {
loading: boolean;
error: TPositionError | null;
coords: GeolocationCoordinates | null;
};
type GeoLocationOptions = {
enableHighAccuracy?: boolean;
maximumAge?: number;
timeout?: number;
retryLimit?: number;
retryDelay?: number;
};
/**
* Custom hook to track the user's geolocation with retry functionality.
*
* @param options - Configuration for geolocation tracking.
* @returns {Object} An object containing:
* - `loading`: Indicates whether location data is being fetched.
* - `error`: Contains error details if location retrieval fails.
* - `coords`: The user's latest coordinates (latitude, longitude, accuracy, etc.).
*
* @example
* import { useGeoLocation } from "hookify-react";
*
* export default function UseGeoLocation() {
* const { loading, error, coords } = useGeoLocation({ enableHighAccuracy: true });
* if (loading) return <p>Fetching location...</p>;
* if (error) return <p>Error: {error.message}</p>;
* return <p>Latitude: {coords?.latitude}, Longitude: {coords?.longitude}</p>;
* }
* ```
*/
declare function useGeoLocation(options?: GeoLocationOptions): TUseLocationReturn;
export { type TUseArrayMethods, useAdvancedEffect, useArray, useClickOutside, useCopyToClipboard, useCounter, useDebounce, useEventListener, useFormState, useGeoLocation, useHistory, useHover, useInterval, useLocalStorage, useOnScreen, useOnlineStatus, usePress, usePrevious, useScrollInfo, useSessionStorage, useSize, useStorage, useTimeout, useToggle, useUpdatedEffect, useWindowSize };