Code Snippets

    A curated collection of useful code snippets, utilities, and helper functions that I use frequently in my projects. Free to use and contribute to.

    Most Popular

    React Hooks
    TypeScript

    useLocalStorage Hook

    A custom React hook for managing localStorage with automatic JSON serialization and type safety.

    import { useState, useEffect } from 'react';
    
    function useLocalStorage<T>(
      key: string,
      initialValue: T
    ): [T, (value: T | ((val: T) => T)) => void] {
      // Get from local storage then parse stored...
    React
    TypeScript
    Hooks
    234
    1200
    Utilities
    JavaScript

    Debounce Function

    A utility function to debounce expensive operations like API calls or search inputs.

    function debounce(func, delay) {
      let timeoutId;
      
      return function executedFunction(...args) {
        const later = () => {
          clearTimeout(timeoutId);
          func.apply(this, args);
        };
        
      ...
    JavaScript
    Performance
    Debounce
    189
    890
    Utilities
    TypeScript

    API Error Handler

    A robust error handling utility for API requests with retry logic and proper error typing.

    interface ApiError {
      message: string;
      status: number;
      code?: string;
    }
    
    interface RetryConfig {
      maxRetries: number;
      delay: number;
      backoff: boolean;
    }
    
    class ApiErrorHandler {
      private st...
    API
    Error Handling
    TypeScript
    278
    567

    All Snippets (6)

    React Hooks
    TypeScript
    234
    1200

    useLocalStorage Hook

    A custom React hook for managing localStorage with automatic JSON serialization and type safety.

    import { useState, useEffect } from 'react';
    
    function useLocalStorage<T>(
      key: string,
      initialValue: T
    ): [T, (value: T | ((val: T) => T)) => void] {
      // Get from local storage then parse stored json or return initialValue
      const [storedValue, setStoredValue] = useState<T>(() => {
        try {
          const item = window.localStorage.getItem(key);
          return item ? JSON.parse(item) : initialValue;
        } catch (error) {
          console.error(`Error reading localStorage key "${key}":`, error);
          return initialValue;
        }
      });
    
      // Return a wrapped version of useState's setter function that persists the new value to localStorage
      const setValue = (value: T | ((val: T) => T)) => {
        try {
          // Allow value to be a function so we have the same API as useState
          const valueToStore = value instanceof Function ? value(storedValue) : value;
          setStoredValue(valueToStore);
          window.localStorage.setItem(key, JSON.stringify(valueToStore));
        } catch (error) {
          console.error(`Error setting localStorage key "${key}":`, error);
        }
      };
    
      return [storedValue, setValue];
    }
    
    // Usage example:
    function App() {
      const [name, setName] = useLocalStorage('name', 'Anonymous');
      
      return (
        <input
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
      );
    }
    React
    TypeScript
    Hooks
    localStorage
    Utilities
    JavaScript
    189
    890

    Debounce Function

    A utility function to debounce expensive operations like API calls or search inputs.

    function debounce(func, delay) {
      let timeoutId;
      
      return function executedFunction(...args) {
        const later = () => {
          clearTimeout(timeoutId);
          func.apply(this, args);
        };
        
        clearTimeout(timeoutId);
        timeoutId = setTimeout(later, delay);
      };
    }
    
    // TypeScript version with proper typing
    function debounce<T extends (...args: any[]) => any>(
      func: T,
      delay: number
    ): (...args: Parameters<T>) => void {
      let timeoutId: NodeJS.Timeout;
      
      return function executedFunction(...args: Parameters<T>) {
        const later = () => {
          clearTimeout(timeoutId);
          func.apply(this, args);
        };
        
        clearTimeout(timeoutId);
        timeoutId = setTimeout(later, delay);
      };
    }
    
    // Usage examples:
    const searchAPI = debounce((query) => {
      fetch(`/api/search?q=${query}`)
        .then(response => response.json())
        .then(data => console.log(data));
    }, 300);
    
    // In React component:
    const handleSearch = debounce((value) => {
      setSearchResults(performSearch(value));
    }, 500);
    JavaScript
    Performance
    Debounce
    Utilities
    CSS
    CSS
    156
    445

    CSS Grid Auto-Fit Cards

    Responsive card layout using CSS Grid that automatically adjusts the number of columns based on available space.

    .cards-container {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
      gap: 1.5rem;
      padding: 1rem;
    }
    
    .card {
      background: white;
      border-radius: 8px;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
      padding: 1.5rem;
      transition: transform 0.2s ease, box-shadow 0.2s ease;
    }
    
    .card:hover {
      transform: translateY(-2px);
      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
    }
    
    /* For smaller cards */
    .cards-container--small {
      grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
      gap: 1rem;
    }
    
    /* For larger cards */
    .cards-container--large {
      grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
      gap: 2rem;
    }
    
    /* Responsive breakpoints */
    @media (max-width: 768px) {
      .cards-container {
        grid-template-columns: 1fr;
        padding: 0.5rem;
      }
    }
    CSS
    Grid
    Responsive
    Layout
    Utilities
    TypeScript
    278
    567

    API Error Handler

    A robust error handling utility for API requests with retry logic and proper error typing.

    interface ApiError {
      message: string;
      status: number;
      code?: string;
    }
    
    interface RetryConfig {
      maxRetries: number;
      delay: number;
      backoff: boolean;
    }
    
    class ApiErrorHandler {
      private static defaultRetryConfig: RetryConfig = {
        maxRetries: 3,
        delay: 1000,
        backoff: true,
      };
    
      static async withRetry<T>(
        apiCall: () => Promise<T>,
        config: Partial<RetryConfig> = {}
      ): Promise<T> {
        const { maxRetries, delay, backoff } = {
          ...this.defaultRetryConfig,
          ...config,
        };
    
        let lastError: Error;
    
        for (let attempt = 0; attempt <= maxRetries; attempt++) {
          try {
            return await apiCall();
          } catch (error) {
            lastError = error as Error;
            
            if (attempt === maxRetries) {
              throw this.formatError(error);
            }
    
            const waitTime = backoff ? delay * Math.pow(2, attempt) : delay;
            await this.sleep(waitTime);
          }
        }
    
        throw this.formatError(lastError!);
      }
    
      private static formatError(error: any): ApiError {
        if (error.response) {
          return {
            message: error.response.data?.message || 'API request failed',
            status: error.response.status,
            code: error.response.data?.code,
          };
        }
    
        return {
          message: error.message || 'Network error occurred',
          status: 0,
        };
      }
    
      private static sleep(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
      }
    }
    
    // Usage example:
    async function fetchUserData(userId: string) {
      try {
        const userData = await ApiErrorHandler.withRetry(
          () => fetch(`/api/users/${userId}`).then(res => res.json()),
          { maxRetries: 2, delay: 500 }
        );
        return userData;
      } catch (error) {
        const apiError = error as ApiError;
        console.error(`Failed to fetch user: ${apiError.message}`);
        throw error;
      }
    }
    API
    Error Handling
    TypeScript
    Async
    React Hooks
    TypeScript
    312
    789

    React Form Validation Hook

    A flexible form validation hook with support for custom rules and real-time validation.

    import { useState, useMemo } from 'react';
    
    type ValidationRule<T> = {
      required?: boolean;
      minLength?: number;
      maxLength?: number;
      pattern?: RegExp;
      custom?: (value: T) => string | undefined;
    };
    
    type ValidationRules<T> = {
      [K in keyof T]?: ValidationRule<T[K]>;
    };
    
    type ValidationErrors<T> = {
      [K in keyof T]?: string;
    };
    
    function useFormValidation<T extends Record<string, any>>(
      initialValues: T,
      rules: ValidationRules<T>
    ) {
      const [values, setValues] = useState<T>(initialValues);
      const [touched, setTouched] = useState<Partial<Record<keyof T, boolean>>>({});
    
      const errors = useMemo(() => {
        const newErrors: ValidationErrors<T> = {};
    
        Object.keys(rules).forEach((key) => {
          const field = key as keyof T;
          const rule = rules[field];
          const value = values[field];
    
          if (!rule) return;
    
          if (rule.required && (!value || value === '')) {
            newErrors[field] = `${String(field)} is required`;
            return;
          }
    
          if (value && rule.minLength && String(value).length < rule.minLength) {
            newErrors[field] = `${String(field)} must be at least ${rule.minLength} characters`;
            return;
          }
    
          if (value && rule.maxLength && String(value).length > rule.maxLength) {
            newErrors[field] = `${String(field)} must be no more than ${rule.maxLength} characters`;
            return;
          }
    
          if (value && rule.pattern && !rule.pattern.test(String(value))) {
            newErrors[field] = `${String(field)} format is invalid`;
            return;
          }
    
          if (rule.custom) {
            const customError = rule.custom(value);
            if (customError) {
              newErrors[field] = customError;
            }
          }
        });
    
        return newErrors;
      }, [values, rules]);
    
      const updateValue = (field: keyof T, value: T[keyof T]) => {
        setValues(prev => ({ ...prev, [field]: value }));
      };
    
      const updateTouched = (field: keyof T) => {
        setTouched(prev => ({ ...prev, [field]: true }));
      };
    
      const isValid = Object.keys(errors).length === 0;
      const hasErrors = (field: keyof T) => touched[field] && errors[field];
    
      return {
        values,
        errors,
        touched,
        isValid,
        updateValue,
        updateTouched,
        hasErrors,
        reset: () => {
          setValues(initialValues);
          setTouched({});
        },
      };
    }
    
    // Usage example:
    function LoginForm() {
      const { values, errors, updateValue, updateTouched, hasErrors, isValid } = 
        useFormValidation(
          { email: '', password: '' },
          {
            email: {
              required: true,
              pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
            },
            password: {
              required: true,
              minLength: 8,
              custom: (value) => {
                if (!/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(value)) {
                  return 'Password must contain uppercase, lowercase and number';
                }
              },
            },
          }
        );
    
      return (
        <form>
          <input
            type="email"
            value={values.email}
            onChange={(e) => updateValue('email', e.target.value)}
            onBlur={() => updateTouched('email')}
          />
          {hasErrors('email') && <span>{errors.email}</span>}
          
          <input
            type="password"
            value={values.password}
            onChange={(e) => updateValue('password', e.target.value)}
            onBlur={() => updateTouched('password')}
          />
          {hasErrors('password') && <span>{errors.password}</span>}
          
          <button type="submit" disabled={!isValid}>
            Login
          </button>
        </form>
      );
    }
    React
    Forms
    Validation
    Hooks
    React Hooks
    TypeScript
    198
    623

    Intersection Observer Hook

    A React hook for detecting when elements enter or leave the viewport, perfect for lazy loading and animations.

    import { useEffect, useRef, useState } from 'react';
    
    interface UseIntersectionObserverProps {
      threshold?: number | number[];
      root?: Element | null;
      rootMargin?: string;
      freezeOnceVisible?: boolean;
    }
    
    function useIntersectionObserver({
      threshold = 0,
      root = null,
      rootMargin = '0%',
      freezeOnceVisible = false,
    }: UseIntersectionObserverProps = {}) {
      const [entry, setEntry] = useState<IntersectionObserverEntry>();
      const [isVisible, setIsVisible] = useState(false);
      const elementRef = useRef<Element>();
    
      const frozen = entry?.isIntersecting && freezeOnceVisible;
    
      const updateEntry = ([entry]: IntersectionObserverEntry[]) => {
        setEntry(entry);
        setIsVisible(entry.isIntersecting);
      };
    
      useEffect(() => {
        const node = elementRef?.current;
        const hasIOSupport = !!window.IntersectionObserver;
    
        if (!hasIOSupport || frozen || !node) return;
    
        const observerParams = { threshold, root, rootMargin };
        const observer = new IntersectionObserver(updateEntry, observerParams);
    
        observer.observe(node);
    
        return () => observer.disconnect();
      }, [elementRef.current, JSON.stringify(threshold), root, rootMargin, frozen]);
    
      return { elementRef, entry, isVisible };
    }
    
    // Usage examples:
    
    // 1. Lazy loading images
    function LazyImage({ src, alt }: { src: string; alt: string }) {
      const { elementRef, isVisible } = useIntersectionObserver({
        threshold: 0.1,
        freezeOnceVisible: true,
      });
    
      return (
        <div ref={elementRef as React.RefObject<HTMLDivElement>}>
          {isVisible ? (
            <img src={src} alt={alt} />
          ) : (
            <div className="placeholder">Loading...</div>
          )}
        </div>
      );
    }
    
    // 2. Fade in animation
    function FadeInSection({ children }: { children: React.ReactNode }) {
      const { elementRef, isVisible } = useIntersectionObserver({
        threshold: 0.3,
        freezeOnceVisible: true,
      });
    
      return (
        <div
          ref={elementRef as React.RefObject<HTMLDivElement>}
          className={`transition-opacity duration-700 ${
            isVisible ? 'opacity-100' : 'opacity-0'
          }`}
        >
          {children}
        </div>
      );
    }
    
    // 3. Infinite scroll
    function useInfiniteScroll(loadMore: () => void) {
      const { elementRef, isVisible } = useIntersectionObserver({
        threshold: 1.0,
      });
    
      useEffect(() => {
        if (isVisible) {
          loadMore();
        }
      }, [isVisible, loadMore]);
    
      return elementRef;
    }
    React
    Intersection Observer
    Performance
    Lazy Loading

    Contribute

    Have a useful code snippet to share? Contribute to the collection and help other developers solve common problems.