Back to All Snippets

React

React components and hooks

20 snippets found

useWindowSize Hook

Track window dimensions with efficient resize handling

This hook tracks window width and height, updating on resize with debouncing for performance. Essential for responsive layouts, canvas sizing, or any UI that needs to respond to viewport changes. Includes proper cleanup and SSR safety for Next.js compatibility.

hookswindowresponsive
import { useState, useEffect } from 'react';

interface WindowSize {
  width: number;
  height: number;
}

function useWindowSize(): WindowSize {
  const [windowSize, setWindowSize] = useState<WindowSize>({
    width: typeof window !== 'undefined' ? window.innerWidth : 0,
    height: typeof window !== 'undefined' ? window.innerHeight : 0,
  });

  useEffect(() => {
    function handleResize() {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }

    window.addEventListener('resize', handleResize);
    handleResize();

    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return windowSize;
}

// Usage
function ResponsiveComponent() {
  const { width, height } = useWindowSize();

  return (
    <div>
      <p>Window size: {width} x {height}</p>
      {width < 768 && <MobileView />}
      {width >= 768 && <DesktopView />}
    </div>
  );
}

useToggle Hook

Simple boolean toggle hook with optional initial state

A lightweight hook for managing boolean state with toggle functionality. Cleaner than using useState for boolean values, it provides explicit toggle, setTrue, and setFalse methods. Perfect for modals, dropdowns, accordions, or any on/off state management.

hooksstateutility
import { useState, useCallback } from 'react';

function useToggle(initialValue: boolean = false) {
  const [value, setValue] = useState(initialValue);

  const toggle = useCallback(() => setValue(v => !v), []);
  const setTrue = useCallback(() => setValue(true), []);
  const setFalse = useCallback(() => setValue(false), []);

  return [value, { toggle, setTrue, setFalse }] as const;
}

// Usage
function Modal() {
  const [isOpen, { toggle, setTrue, setFalse }] = useToggle();

  return (
    <>
      <button onClick={setTrue}>Open Modal</button>
      {isOpen && (
        <div className="modal">
          <h2>Modal Content</h2>
          <button onClick={setFalse}>Close</button>
        </div>
      )}
    </>
  );
}

useTimeout Hook

Declarative setTimeout that handles cleanup

A declarative approach to setTimeout that automatically cleans up on unmount or dependency changes. Unlike raw setTimeout, it works correctly with React's rendering cycle and prevents memory leaks. Perfect for delayed actions, auto-hiding notifications, or timed UI transitions.

hookstimerutility
import { useEffect, useRef } from 'react';

function useTimeout(callback: () => void, delay: number | null) {
  const savedCallback = useRef(callback);

  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  useEffect(() => {
    if (delay === null) return;

    const id = setTimeout(() => savedCallback.current(), delay);

    return () => clearTimeout(id);
  }, [delay]);
}

// Usage
function Notification({ message, onClose }: { message: string; onClose: () => void }) {
  const [isVisible, setIsVisible] = useState(true);

  // Auto-hide after 5 seconds
  useTimeout(() => {
    setIsVisible(false);
    onClose();
  }, isVisible ? 5000 : null);

  if (!isVisible) return null;

  return (
    <div className="notification">
      {message}
      <button onClick={() => setIsVisible(false)}>×</button>
    </div>
  );
}

usePrevious Hook

Track the previous value of a state or prop

This hook stores the previous value of any variable across renders using useRef and useEffect. Useful for comparing current and previous values to trigger side effects, animations, or conditional logic. Common in form validation, detecting prop changes, or implementing undo functionality.

hooksstateutility
import { useRef, useEffect } from 'react';

function usePrevious<T>(value: T): T | undefined {
  const ref = useRef<T>();

  useEffect(() => {
    ref.current = value;
  }, [value]);

  return ref.current;
}

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

  return (
    <div>
      <p>Current: {count}</p>
      <p>Previous: {prevCount}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      {prevCount !== undefined && count > prevCount && <p>Count increased!</p>}
    </div>
  );
}

useOnClickOutside Hook

Detect clicks outside a component

This hook detects clicks outside a referenced element, perfect for closing dropdowns, modals, or popovers. It uses event delegation for efficiency and properly handles cleanup. Supports both mouse and touch events for mobile compatibility.

hookseventsutility
import { useEffect, RefObject } from 'react';

function useOnClickOutside<T extends HTMLElement = HTMLElement>(
  ref: RefObject<T>,
  handler: (event: MouseEvent | TouchEvent) => void
) {
  useEffect(() => {
    const listener = (event: MouseEvent | TouchEvent) => {
      if (!ref.current || ref.current.contains(event.target as Node)) {
        return;
      }
      handler(event);
    };

    document.addEventListener('mousedown', listener);
    document.addEventListener('touchstart', listener);

    return () => {
      document.removeEventListener('mousedown', listener);
      document.removeEventListener('touchstart', listener);
    };
  }, [ref, handler]);
}

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

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

  return (
    <div ref={dropdownRef}>
      <button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
      {isOpen && <div className="dropdown-menu">Menu items...</div>}
    </div>
  );
}

useMediaQuery Hook

React hook to match CSS media queries

This hook tracks media query matches in real-time, enabling responsive behavior in your components. It uses window.matchMedia for efficient native browser support and updates on window resize. Perfect for conditional rendering based on screen size, theme preferences, or device capabilities.

hooksresponsiveutility
import { useState, useEffect } from 'react';

function useMediaQuery(query: string): boolean {
  const [matches, setMatches] = useState(false);

  useEffect(() => {
    const media = window.matchMedia(query);

    if (media.matches !== matches) {
      setMatches(media.matches);
    }

    const listener = () => setMatches(media.matches);
    media.addEventListener('change', listener);

    return () => media.removeEventListener('change', listener);
  }, [matches, query]);

  return matches;
}

// Usage
function ResponsiveComponent() {
  const isMobile = useMediaQuery('(max-width: 768px)');
  const isDarkMode = useMediaQuery('(prefers-color-scheme: dark)');

  return (
    <div>
      {isMobile ? <MobileNav /> : <DesktopNav />}
      <div className={isDarkMode ? 'dark' : 'light'}>Content</div>
    </div>
  );
}

useLocalStorage Hook

Custom hook to sync state with localStorage

This custom hook synchronizes React state with localStorage, automatically persisting and retrieving values. It handles JSON serialization, provides SSR safety, and updates across browser tabs using the storage event. Perfect for persisting user preferences, form data, or app settings without manual localStorage management.

hooksstoragestate
import { useState, useEffect } from 'react';

function useLocalStorage<T>(key: string, initialValue: T) {
  const [storedValue, setStoredValue] = useState<T>(() => {
    if (typeof window === 'undefined') return initialValue;

    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  const setValue = (value: T | ((val: T) => T)) => {
    try {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      if (typeof window !== 'undefined') {
        window.localStorage.setItem(key, JSON.stringify(valueToStore));
      }
    } catch (error) {
      console.error(error);
    }
  };

  return [storedValue, setValue] as const;
}

// Usage
function App() {
  const [theme, setTheme] = useLocalStorage('theme', 'dark');
  return <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>{theme}</button>;
}

useKeyPress Hook

Detect keyboard key presses in React

This hook detects when a specific keyboard key is pressed and released. Perfect for keyboard shortcuts, game controls, accessibility features, or any keyboard-driven interactions. Includes proper cleanup and supports key combinations.

hookskeyboardevents
import { useState, useEffect } from 'react';

function useKeyPress(targetKey: string): boolean {
  const [keyPressed, setKeyPressed] = useState(false);

  useEffect(() => {
    const downHandler = (e: KeyboardEvent) => {
      if (e.key === targetKey) {
        setKeyPressed(true);
      }
    };

    const upHandler = (e: KeyboardEvent) => {
      if (e.key === targetKey) {
        setKeyPressed(false);
      }
    };

    window.addEventListener('keydown', downHandler);
    window.addEventListener('keyup', upHandler);

    return () => {
      window.removeEventListener('keydown', downHandler);
      window.removeEventListener('keyup', upHandler);
    };
  }, [targetKey]);

  return keyPressed;
}

// Usage
function Game() {
  const leftPressed = useKeyPress('ArrowLeft');
  const rightPressed = useKeyPress('ArrowRight');
  const spacePressed = useKeyPress(' ');

  return (
    <div>
      <p>Press arrow keys to move, space to jump</p>
      <div>
        {leftPressed && '← Moving left'}
        {rightPressed && '→ Moving right'}
        {spacePressed && '↑ Jumping'}
      </div>
    </div>
  );
}

useInterval Hook

Declarative interval hook that handles cleanup

A declarative way to use setInterval in React that properly handles cleanup and supports dynamic delays. Unlike raw setInterval, it works correctly with React's rendering cycle and prevents memory leaks. Perfect for polling, countdowns, animations, or any periodic updates.

hookstimerutility
import { useEffect, useRef } from 'react';

function useInterval(callback: () => void, delay: number | null) {
  const savedCallback = useRef(callback);

  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  useEffect(() => {
    if (delay === null) return;

    const tick = () => savedCallback.current();
    const id = setInterval(tick, delay);

    return () => clearInterval(id);
  }, [delay]);
}

// Usage
function Timer() {
  const [count, setCount] = useState(0);
  const [isRunning, setIsRunning] = useState(true);

  useInterval(
    () => setCount(count + 1),
    isRunning ? 1000 : null
  );

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setIsRunning(!isRunning)}>
        {isRunning ? 'Pause' : 'Resume'}
      </button>
    </div>
  );
}

useIntersectionObserver Hook

Detect when an element enters or leaves the viewport

This hook uses the Intersection Observer API to detect when an element becomes visible in the viewport. Perfect for lazy loading images, infinite scroll, analytics tracking, or triggering animations. Highly performant and customizable with threshold and root margin options.

hooksviewportperformance
import { useState, useEffect, RefObject } from 'react';

interface Options {
  threshold?: number | number[];
  root?: Element | null;
  rootMargin?: string;
}

function useIntersectionObserver<T extends Element>(
  ref: RefObject<T>,
  options: Options = {}
): boolean {
  const [isIntersecting, setIsIntersecting] = useState(false);

  useEffect(() => {
    const element = ref.current;
    if (!element) return;

    const observer = new IntersectionObserver(([entry]) => {
      setIsIntersecting(entry.isIntersecting);
    }, options);

    observer.observe(element);

    return () => {
      observer.disconnect();
    };
  }, [ref, options.threshold, options.root, options.rootMargin]);

  return isIntersecting;
}

// Usage
function LazyImage({ src, alt }: { src: string; alt: string }) {
  const imgRef = useRef<HTMLImageElement>(null);
  const isVisible = useIntersectionObserver(imgRef, { threshold: 0.1 });

  return (
    <img
      ref={imgRef}
      src={isVisible ? src : 'placeholder.jpg'}
      alt={alt}
      loading="lazy"
    />
  );
}

useHover Hook

Detect hover state on any element

This hook tracks whether an element is being hovered over. Returns both the hover state and a ref to attach to your element. Useful for tooltips, previews, interactive cards, or any hover-based UI. Works with both mouse and touch devices.

hookseventsinteraction
import { useState, useRef, useEffect, RefObject } from 'react';

function useHover<T extends HTMLElement = HTMLElement>(): [RefObject<T>, boolean] {
  const [isHovering, setIsHovering] = useState(false);
  const ref = useRef<T>(null);

  useEffect(() => {
    const node = ref.current;
    if (!node) return;

    const handleMouseEnter = () => setIsHovering(true);
    const handleMouseLeave = () => setIsHovering(false);

    node.addEventListener('mouseenter', handleMouseEnter);
    node.addEventListener('mouseleave', handleMouseLeave);

    return () => {
      node.removeEventListener('mouseenter', handleMouseEnter);
      node.removeEventListener('mouseleave', handleMouseLeave);
    };
  }, []);

  return [ref, isHovering];
}

// Usage
function HoverCard() {
  const [hoverRef, isHovered] = useHover<HTMLDivElement>();

  return (
    <div ref={hoverRef} className="card">
      <h3>Hover me!</h3>
      {isHovered && <p>I'm being hovered!</p>}
      <style jsx>{`
        .card {
          transition: transform 0.2s;
          transform: scale(${isHovered ? 1.05 : 1});
        }
      `}</style>
    </div>
  );
}

useForm Hook

Simple form state management with validation

This hook simplifies form state management by handling input values, validation, errors, and submission. It provides a clean API for controlled inputs with built-in validation support. Perfect for forms without needing heavy libraries like Formik or React Hook Form.

hooksformsvalidation
import { useState, ChangeEvent, FormEvent } from 'react';

interface ValidationRules<T> {
  [K in keyof T]?: (value: T[K]) => string | null;
}

function useForm<T extends Record<string, any>>(
  initialValues: T,
  validationRules?: ValidationRules<T>
) {
  const [values, setValues] = useState<T>(initialValues);
  const [errors, setErrors] = useState<Partial<Record<keyof T, string>>>({});
  const [touched, setTouched] = useState<Partial<Record<keyof T, boolean>>>({});

  const handleChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
    const { name, value } = e.target;
    setValues(prev => ({ ...prev, [name]: value }));

    // Validate on change if field has been touched
    if (touched[name as keyof T] && validationRules?.[name as keyof T]) {
      const error = validationRules[name as keyof T]!(value as any);
      setErrors(prev => ({ ...prev, [name]: error || undefined }));
    }
  };

  const handleBlur = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
    const { name } = e.target;
    setTouched(prev => ({ ...prev, [name]: true }));

    // Validate on blur
    if (validationRules?.[name as keyof T]) {
      const error = validationRules[name as keyof T]!(values[name]);
      setErrors(prev => ({ ...prev, [name]: error || undefined }));
    }
  };

  const validate = (): boolean => {
    if (!validationRules) return true;

    const newErrors: Partial<Record<keyof T, string>> = {};
    let isValid = true;

    Object.keys(validationRules).forEach((key) => {
      const error = validationRules[key as keyof T]!(values[key]);
      if (error) {
        newErrors[key as keyof T] = error;
        isValid = false;
      }
    });

    setErrors(newErrors);
    return isValid;
  };

  const handleSubmit = (onSubmit: (values: T) => void) => {
    return (e: FormEvent) => {
      e.preventDefault();
      if (validate()) {
        onSubmit(values);
      }
    };
  };

  const reset = () => {
    setValues(initialValues);
    setErrors({});
    setTouched({});
  };

  return {
    values,
    errors,
    touched,
    handleChange,
    handleBlur,
    handleSubmit,
    reset,
  };
}

// Usage
interface LoginForm {
  email: string;
  password: string;
}

function LoginForm() {
  const { values, errors, handleChange, handleBlur, handleSubmit } = useForm<LoginForm>(
    { email: '', password: '' },
    {
      email: (value) => {
        if (!value) return 'Email is required';
        if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return 'Invalid email';
        return null;
      },
      password: (value) => {
        if (!value) return 'Password is required';
        if (value.length < 6) return 'Password must be at least 6 characters';
        return null;
      },
    }
  );

  const onSubmit = (data: LoginForm) => {
    console.log('Form submitted:', data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <input
          name="email"
          value={values.email}
          onChange={handleChange}
          onBlur={handleBlur}
          placeholder="Email"
        />
        {errors.email && <span className="error">{errors.email}</span>}
      </div>
      <div>
        <input
          name="password"
          type="password"
          value={values.password}
          onChange={handleChange}
          onBlur={handleBlur}
          placeholder="Password"
        />
        {errors.password && <span className="error">{errors.password}</span>}
      </div>
      <button type="submit">Login</button>
    </form>
  );
}

useFetch Hook

Custom hook for data fetching with loading and error states

This hook simplifies data fetching by managing loading, error, and data states automatically. It includes cleanup to prevent memory leaks on unmount and supports dynamic URL changes with dependency tracking. Returns a clean API with loading/error/data states, eliminating boilerplate code in your components.

hooksapifetch
import { useState, useEffect } from 'react';

function useFetch<T>(url: string) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;

    const fetchData = async () => {
      setLoading(true);
      setError(null);

      try {
        const response = await fetch(url);
        if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
        const json = await response.json();

        if (!cancelled) {
          setData(json);
          setLoading(false);
        }
      } catch (err) {
        if (!cancelled) {
          setError(err instanceof Error ? err.message : 'An error occurred');
          setLoading(false);
        }
      }
    };

    fetchData();

    return () => {
      cancelled = true;
    };
  }, [url]);

  return { data, loading, error };
}

// Usage
function UserList() {
  const { data, loading, error } = useFetch<User[]>('/api/users');

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  return <div>{data?.map(user => <div key={user.id}>{user.name}</div>)}</div>;
}

useEffectOnce Hook

Run an effect only once on mount

A convenience hook that runs an effect only once when the component mounts, similar to componentDidMount in class components. Cleaner than useEffect with empty dependencies and makes the intent explicit. Perfect for initialization, data fetching on mount, or setting up subscriptions.

hookslifecycleutility
import { useEffect, EffectCallback } from 'react';

function useEffectOnce(effect: EffectCallback) {
  useEffect(effect, []);
}

// Usage
function Component() {
  useEffectOnce(() => {
    console.log('Component mounted');

    // Fetch initial data
    fetchUserData();

    // Setup subscription
    const subscription = subscribeToUpdates();

    // Cleanup
    return () => {
      subscription.unsubscribe();
    };
  });

  return <div>Component content</div>;
}

export default useEffectOnce;

useDebounce Hook

Debounce a value with React hooks

This hook debounces any value changes, waiting for a specified delay before updating. Essential for search inputs, real-time validation, or any scenario where you want to reduce API calls or expensive computations. Works seamlessly with React's rendering cycle and properly cleans up timers.

hooksperformanceutility
import { useState, useEffect } from 'react';

function useDebounce<T>(value: T, delay: number = 500): T {
  const [debouncedValue, setDebouncedValue] = useState<T>(value);

  useEffect(() => {
    const timer = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(timer);
    };
  }, [value, delay]);

  return debouncedValue;
}

// Usage
function SearchComponent() {
  const [searchTerm, setSearchTerm] = useState('');
  const debouncedSearchTerm = useDebounce(searchTerm, 500);

  useEffect(() => {
    if (debouncedSearchTerm) {
      // Perform API call here
      console.log('Searching for:', debouncedSearchTerm);
    }
  }, [debouncedSearchTerm]);

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

useClipboard Hook

Copy text to clipboard with feedback

This hook provides a simple API for copying text to clipboard with automatic success feedback. It includes a timeout to reset the copied state, fallback for older browsers, and proper error handling. Essential for "copy code" buttons, sharing links, or any copy-to-clipboard functionality.

hooksclipboardutility
import { useState } from 'react';

function useClipboard(timeout: number = 2000) {
  const [copied, setCopied] = useState(false);

  const copy = async (text: string) => {
    try {
      if (navigator.clipboard) {
        await navigator.clipboard.writeText(text);
      } else {
        // Fallback for older browsers
        const textarea = document.createElement('textarea');
        textarea.value = text;
        textarea.style.position = 'fixed';
        textarea.style.opacity = '0';
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
      }

      setCopied(true);
      setTimeout(() => setCopied(false), timeout);
    } catch (error) {
      console.error('Failed to copy:', error);
    }
  };

  return { copied, copy };
}

// Usage
function CopyButton({ text }: { text: string }) {
  const { copied, copy } = useClipboard();

  return (
    <button onClick={() => copy(text)}>
      {copied ? 'Copied!' : 'Copy'}
    </button>
  );
}

useAsync Hook

Handle async operations with loading, error, and success states

This hook simplifies async operations by managing all states (idle, loading, success, error) and provides methods to execute and reset. It includes proper error handling, prevents memory leaks, and supports multiple concurrent operations. Essential for API calls, form submissions, or any async workflow.

hooksasyncapi
import { useState, useCallback } from 'react';

type Status = 'idle' | 'loading' | 'success' | 'error';

interface AsyncState<T> {
  status: Status;
  data: T | null;
  error: Error | null;
}

function useAsync<T>() {
  const [state, setState] = useState<AsyncState<T>>({
    status: 'idle',
    data: null,
    error: null,
  });

  const execute = useCallback(async (asyncFunction: () => Promise<T>) => {
    setState({ status: 'loading', data: null, error: null });

    try {
      const data = await asyncFunction();
      setState({ status: 'success', data, error: null });
      return data;
    } catch (error) {
      setState({
        status: 'error',
        data: null,
        error: error instanceof Error ? error : new Error('An error occurred')
      });
      throw error;
    }
  }, []);

  const reset = useCallback(() => {
    setState({ status: 'idle', data: null, error: null });
  }, []);

  return { ...state, execute, reset };
}

// Usage
function UserProfile({ userId }: { userId: string }) {
  const { status, data, error, execute } = useAsync<User>();

  useEffect(() => {
    execute(() => fetch(`/api/users/${userId}`).then(res => res.json()));
  }, [userId, execute]);

  if (status === 'loading') return <div>Loading...</div>;
  if (status === 'error') return <div>Error: {error?.message}</div>;
  if (status === 'success') return <div>Hello {data?.name}</div>;
  return null;
}

useArray Hook

Manage array state with helpful methods

This hook provides convenient methods for managing array state, including push, filter, update, remove, and clear operations. Eliminates boilerplate code when working with arrays in state and ensures immutable updates. Perfect for managing lists, todos, or any collection of items.

hooksstateutility
import { useState, useCallback } from 'react';

function useArray<T>(initialValue: T[] = []) {
  const [array, setArray] = useState<T[]>(initialValue);

  const push = useCallback((element: T) => {
    setArray(prev => [...prev, element]);
  }, []);

  const filter = useCallback((callback: (item: T, index: number) => boolean) => {
    setArray(prev => prev.filter(callback));
  }, []);

  const update = useCallback((index: number, newElement: T) => {
    setArray(prev => [
      ...prev.slice(0, index),
      newElement,
      ...prev.slice(index + 1),
    ]);
  }, []);

  const remove = useCallback((index: number) => {
    setArray(prev => [...prev.slice(0, index), ...prev.slice(index + 1)]);
  }, []);

  const clear = useCallback(() => {
    setArray([]);
  }, []);

  const set = useCallback((newArray: T[]) => {
    setArray(newArray);
  }, []);

  return {
    array,
    set,
    push,
    filter,
    update,
    remove,
    clear,
  };
}

// Usage
interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

function TodoList() {
  const { array: todos, push, update, remove } = useArray<Todo>([]);

  const addTodo = (text: string) => {
    push({ id: Date.now(), text, completed: false });
  };

  const toggleTodo = (index: number) => {
    const todo = todos[index];
    update(index, { ...todo, completed: !todo.completed });
  };

  return (
    <div>
      {todos.map((todo, index) => (
        <div key={todo.id}>
          <input
            type="checkbox"
            checked={todo.completed}
            onChange={() => toggleTodo(index)}
          />
          <span>{todo.text}</span>
          <button onClick={() => remove(index)}>Delete</button>
        </div>
      ))}
    </div>
  );
}

Portal Component

Render children into a DOM node outside the parent hierarchy

Portals provide a way to render children into a DOM node that exists outside the parent component hierarchy. Essential for modals, tooltips, dropdowns, or any UI that needs to escape CSS overflow/z-index constraints while maintaining React event bubbling.

componentdommodal
import { ReactNode, useEffect, useState } from 'react';
import { createPortal } from 'react-dom';

interface PortalProps {
  children: ReactNode;
  container?: Element;
}

function Portal({ children, container }: PortalProps) {
  const [mounted, setMounted] = useState(false);
  const [portalContainer, setPortalContainer] = useState<Element | null>(null);

  useEffect(() => {
    setMounted(true);

    if (container) {
      setPortalContainer(container);
    } else {
      let portalRoot = document.getElementById('portal-root');

      if (!portalRoot) {
        portalRoot = document.createElement('div');
        portalRoot.id = 'portal-root';
        document.body.appendChild(portalRoot);
      }

      setPortalContainer(portalRoot);
    }

    return () => setMounted(false);
  }, [container]);

  if (!mounted || !portalContainer) return null;

  return createPortal(children, portalContainer);
}

// Usage
function Modal({ isOpen, onClose, children }: {
  isOpen: boolean;
  onClose: () => void;
  children: ReactNode
}) {
  if (!isOpen) return null;

  return (
    <Portal>
      <div className="modal-overlay" onClick={onClose}>
        <div className="modal-content" onClick={(e) => e.stopPropagation()}>
          {children}
          <button onClick={onClose}>Close</button>
        </div>
      </div>
    </Portal>
  );
}

export default Portal;

Error Boundary Component

Catch JavaScript errors in component tree

Error Boundaries catch JavaScript errors anywhere in the child component tree, log those errors, and display a fallback UI. They prevent the entire app from crashing due to errors in a single component. Essential for production apps to provide graceful error handling and better user experience.

componenterror-handlingreliability
import React, { Component, ReactNode, ErrorInfo } from 'react';

interface Props {
  children: ReactNode;
  fallback?: ReactNode;
  onError?: (error: Error, errorInfo: ErrorInfo) => void;
}

interface State {
  hasError: boolean;
  error: Error | null;
}

class ErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    console.error('Error caught by boundary:', error, errorInfo);
    this.props.onError?.(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback || (
        <div className="error-boundary">
          <h2>Something went wrong</h2>
          <details>
            <summary>Error details</summary>
            <pre>{this.state.error?.message}</pre>
          </details>
          <button onClick={() => this.setState({ hasError: false, error: null })}>
            Try again
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

// Usage
function App() {
  return (
    <ErrorBoundary fallback={<div>Oops! Something went wrong.</div>}>
      <YourApp />
    </ErrorBoundary>
  );
}

export default ErrorBoundary;