npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-essentials-functions

v1.1.0

Published

A collection of zero-dependency useful hooks and components for React

Downloads

125

Readme

react-essentials-functions

A collection of zero-dependency useful hooks and components for React.

Installation

yarn add react-essentials-functions
# or
npm install react-essentials-functions

Table of Contents


Hooks

useClickOutside

Hook that detects clicks outside of a referenced element. Useful for closing dropdowns, modals, and popovers. Listens for both mousedown and touchstart events.

Parameters:

  • ref: RefObject<HTMLElement> - React ref to the element to monitor
  • handler: (event: MouseEvent | TouchEvent) => void - Callback fired when a click outside is detected

Returns:

  • void

Side effects:

  • Adds mousedown and touchstart event listeners on document
  • Removes listeners on unmount

Example:

import { useClickOutside } from 'react-essentials-functions';
import { useRef, useState } from 'react';

function Dropdown() {
  const dropdownRef = useRef<HTMLDivElement>(null);
  const [isOpen, setIsOpen] = useState(false);

  useClickOutside(dropdownRef, () => setIsOpen(false));

  return (
    <div ref={dropdownRef}>
      <button onClick={() => setIsOpen(true)}>Open</button>
      {isOpen && <ul><li>Option 1</li><li>Option 2</li></ul>}
    </div>
  );
}

useDebounce

Hook that debounces a value by a given delay. The debounced value will only update after the specified delay has passed since the last change. Useful for search inputs, API calls, and any rapid-fire updates.

Type Parameters:

  • T - The type of the value to debounce

Parameters:

  • value: T - The value to debounce
  • delay: number - The debounce delay in milliseconds

Returns:

  • T - The debounced value

Example:

import { useDebounce } from 'react-essentials-functions';
import { useState, useEffect } from 'react';

function SearchComponent() {
  const [searchTerm, setSearchTerm] = useState('');
  const debouncedSearch = useDebounce(searchTerm, 300);

  useEffect(() => {
    if (debouncedSearch) {
      // This only fires 300ms after the user stops typing
      fetchResults(debouncedSearch);
    }
  }, [debouncedSearch]);

  return (
    <input
      value={searchTerm}
      onChange={(e) => setSearchTerm(e.target.value)}
      placeholder="Search..."
    />
  );
}

useDimensions

Hook to get the dimensions of a DOM element. Uses ResizeObserver for optimal performance with a fallback to window events for older browsers.

Parameters:

  • targetRef: RefObject<HTMLElement> - React ref to the element to measure

Returns:

  • Dimensions - Object containing width and height of the element

Side effects:

  • Creates a ResizeObserver on the target element (or falls back to resize/scroll window listeners)
  • Cleans up on unmount

Example:

import { useDimensions } from 'react-essentials-functions';
import { useRef } from 'react';

function MyComponent() {
  const targetRef = useRef<HTMLDivElement>(null);
  const { width, height } = useDimensions(targetRef);

  return (
    <div ref={targetRef}>
      Size: {width}px x {height}px
    </div>
  );
}

useLocalStorage

Hook that syncs state with localStorage. Handles JSON serialization/deserialization automatically. Falls back gracefully when localStorage is unavailable (SSR, private browsing).

Type Parameters:

  • T - The type of the stored value

Parameters:

  • key: string - The localStorage key
  • initialValue: T - The initial value if nothing is stored

Returns:

  • [T, (value: T | ((prev: T) => T)) => void, () => void] - A tuple containing:
    • The current stored value
    • A setter function (accepts value or updater function)
    • A remove function to clear the key from localStorage

Side effects:

  • Reads from localStorage on initialization
  • Writes to localStorage on every value change
  • removeValue deletes the key from localStorage

Example:

import { useLocalStorage } from 'react-essentials-functions';

function Settings() {
  const [name, setName, removeName] = useLocalStorage('user-name', '');
  const [preferences, setPreferences] = useLocalStorage('prefs', {
    notifications: true,
    language: 'en',
  });

  return (
    <div>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <button onClick={removeName}>Clear name</button>
      <button onClick={() => setPreferences(prev => ({ ...prev, language: 'fr' }))}>
        Switch to French
      </button>
    </div>
  );
}

useMediaQuery

Hook that tracks whether a CSS media query matches. Listens for changes and updates automatically. Useful for responsive design, detecting dark mode preference, reduced motion, etc.

Parameters:

  • query: string - The CSS media query string (e.g. '(min-width: 768px)')

Returns:

  • boolean - Whether the media query currently matches

Side effects:

  • Adds a change listener on the MediaQueryList object
  • Removes listener on unmount or query change

Example:

import { useMediaQuery } from 'react-essentials-functions';

function ResponsiveComponent() {
  const isMobile = useMediaQuery('(max-width: 767px)');
  const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');
  const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');

  return (
    <div>
      {isMobile ? <MobileLayout /> : <DesktopLayout />}
      {prefersDark && <span>Dark mode detected</span>}
    </div>
  );
}

usePrevious

Hook that returns the previous value of a variable. Useful for comparing current and previous props or state values.

Type Parameters:

  • T - The type of the tracked value

Parameters:

  • value: T - The value to track

Returns:

  • T | undefined - The value from the previous render, or undefined on first render

Example:

import { usePrevious } from 'react-essentials-functions';
import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  const previousCount = usePrevious(count);

  return (
    <div>
      <p>Current: {count}, Previous: {previousCount ?? 'N/A'}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

useSafeFetch

Hook that provides a fetch function which automatically aborts previous requests and cleans up on unmount using AbortController. Prevents race conditions when multiple requests are made in sequence.

Parameters:

  • None

Returns:

  • (url: string, options?: RequestInit) => Promise<Response> - Fetch function with automatic abort handling

Side effects:

  • Aborts the previous in-flight request when a new one is made
  • Aborts any pending request on component unmount
  • User-provided signal in options is ignored (the hook manages its own)

Example:

import { useSafeFetch } from 'react-essentials-functions';
import { useEffect } from 'react';

function DataComponent() {
  const safeFetch = useSafeFetch();

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await safeFetch('https://api.example.com/data');
        const data = await response.json();
      } catch (error) {
        if (error.name !== 'AbortError') {
          console.error('Fetch error:', error);
        }
      }
    };

    fetchData();
  }, [safeFetch]);

  return <div>Loading data...</div>;
}

useSafeState

A version of useState that prevents state updates after the component unmounts, preventing memory leaks and "Can't perform a React state update on an unmounted component" warnings.

Type Parameters:

  • T - The type of the state value

Parameters:

  • initialValue: T | (() => T) - The initial state value

Returns:

  • [T, (value: T | ((prevState: T) => T)) => void] - A tuple containing the current state and a safe setState function

Example:

import { useSafeState } from 'react-essentials-functions';
import { useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useSafeState<User | null>(null);

  useEffect(() => {
    fetchUser(userId).then((data) => {
      // Safe even if component unmounted during fetch
      setUser(data);
    });
  }, [userId]);

  return user ? <div>{user.name}</div> : <div>Loading...</div>;
}

useScript

Hook to dynamically load external scripts with status tracking and callback support.

Parameters:

  • url: string - The URL of the script to load
  • options?: UseScriptOptions - Optional configuration:
    • onLoad?: () => void - Callback when script loads successfully
    • onError?: () => void - Callback when script fails to load
    • removeOnUnmount?: boolean - Whether to remove script on unmount (default: true)

Returns:

  • UseScriptStatus - The current status: 'idle' | 'loading' | 'ready' | 'error'

Side effects:

  • Appends a <script> tag to document.body
  • Removes the script tag on unmount (unless removeOnUnmount: false)
  • Detects and reuses already-loaded scripts

Example:

import { useScript } from 'react-essentials-functions';

function GoogleMapsComponent() {
  const status = useScript('https://maps.googleapis.com/maps/api/js', {
    onLoad: () => console.log('Google Maps loaded'),
    onError: () => console.error('Failed to load Google Maps'),
  });

  if (status === 'loading') return <div>Loading map...</div>;
  if (status === 'error') return <div>Error loading map</div>;
  if (status === 'idle') return <div>Initializing...</div>;

  return <div>Map is ready!</div>;
}

useTheme

Hook to manage theme (light/dark) with localStorage persistence and SSR support. Automatically detects system color scheme preference via prefers-color-scheme when no theme has been previously stored.

Returns:

  • [ThemeMode, () => void, boolean] - A tuple containing:
    • Current theme mode ('light' | 'dark')
    • Function to toggle between themes
    • Boolean indicating if component is mounted (useful for SSR)

Side effects:

  • Reads/writes to localStorage with key 'theme'
  • Detects system prefers-color-scheme preference on first load

Example:

import { useTheme } from 'react-essentials-functions';

function ThemeToggle() {
  const [theme, toggleTheme, mounted] = useTheme();

  // Avoid hydration mismatch
  if (!mounted) return null;

  return (
    <button onClick={toggleTheme}>
      Switch to {theme === 'light' ? 'dark' : 'light'} mode
    </button>
  );
}

useToggle

Hook for managing a boolean toggle state. Provides a simple API for toggling, setting true, or setting false. Useful for modals, dropdowns, accordions, etc.

Parameters:

  • initialValue?: boolean - The initial boolean value (default: false)

Returns:

  • [boolean, () => void, () => void, () => void] - A tuple containing:
    • The current boolean value
    • toggle - Flips the value
    • setTrue - Sets to true
    • setFalse - Sets to false

Example:

import { useToggle } from 'react-essentials-functions';

function Modal() {
  const [isOpen, toggleOpen, open, close] = useToggle(false);

  return (
    <div>
      <button onClick={open}>Open Modal</button>
      {isOpen && (
        <div className="modal">
          <p>Modal content</p>
          <button onClick={close}>Close</button>
        </div>
      )}
    </div>
  );
}

useWindowDimensions

Hook to get the current window dimensions with automatic updates on resize. SSR-safe (returns 0 for both dimensions when window is unavailable).

Returns:

  • WindowDimensions - Object containing width and height of the window

Side effects:

  • Adds a resize event listener on window
  • Removes listener on unmount

Example:

import { useWindowDimensions } from 'react-essentials-functions';

function ResponsiveComponent() {
  const { width, height } = useWindowDimensions();

  return (
    <div>
      Window size: {width}px x {height}px
      {width < 768 ? <MobileLayout /> : <DesktopLayout />}
    </div>
  );
}

Components

ConditionalWrapper

Component that conditionally wraps its children with a wrapper component based on a condition. When the condition is false, children are rendered unwrapped inside a fragment.

Props:

  • condition: boolean - Whether to wrap the children
  • wrapper: (children: React.ReactNode) => JSX.Element - Function that returns the wrapper element
  • children: React.ReactNode - Children to wrap

Example:

import { ConditionalWrapper } from 'react-essentials-functions';

function LinkWrapper({ link, children }) {
  return (
    <ConditionalWrapper
      condition={!!link}
      wrapper={(c) => <a href={link}>{c}</a>}
    >
      <button>{children}</button>
    </ConditionalWrapper>
  );
}

TypeScript Support

This library is written in TypeScript and includes full type definitions. All types are exported for your convenience:

import type {
  Dimensions,
  WindowDimensions,
  ThemeMode,
  UseScriptStatus,
  UseScriptOptions,
  ConditionalWrapperProps,
} from 'react-essentials-functions';

License

MIT