A collection of reusable code fragments, utility functions, and hooks I've curated over the years. Copy, paste, and ship faster.
Create a deep copy of objects and arrays, avoiding reference issues.
export function deepClone<T>(obj: T): T {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime()) as unknown as T;
}
if (obj instanceof Array) {
return obj.map(item => deepClone(item)) as unknown as T;
}
if (typeof obj === 'object') {
const clonedObj = {} as T;
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]);
}
}
return clonedObj;
}
return obj;
}Format dates consistently across your application with a simple utility function.
export function formatDate(
date: Date | string | number,
options: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: 'long',
day: 'numeric',
}
): string {
const dateObj = typeof date === 'string' || typeof date === 'number'
? new Date(date)
: date;
return new Intl.DateTimeFormat('en-US', options).format(dateObj);
}Generate unique identifiers for keys, temporary IDs, and unique values.
// Simple counter-based ID
let idCounter = 0;
export function generateId(prefix: string = 'id'): string {
return `${prefix}-${++idCounter}`;
}
// Timestamp-based ID
export function generateTimestampId(): string {
return `id-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
// UUID-like string
export function generateUUID(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0;
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
// Short unique ID
export function generateShortId(): string {
return Math.random().toString(36).substr(2, 9);
}export const sleep = (ms: number): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, ms));Copy text to clipboard with a simple React hook that handles success and error states.
import { useState, useCallback } from 'react';
interface UseCopyToClipboardReturn {
copy: (text: string) => Promise<void>;
isCopied: boolean;
error: Error | null;
}
export function useCopyToClipboard(): UseCopyToClipboardReturn {
const [isCopied, setIsCopied] = useState(false);
const [error, setError] = useState<Error | null>(null);
const copy = useCallback(async (text: string) => {
try {
await navigator.clipboard.writeText(text);
setIsCopied(true);
setError(null);
// Reset after 2 seconds
setTimeout(() => setIsCopied(false), 2000);
} catch (err) {
setError(err instanceof Error ? err : new Error('Failed to copy'));
setIsCopied(false);
}
}, []);
return { copy, isCopied, error };
}Detect when an element enters or leaves the viewport using the Intersection Observer API.
import { useEffect, useRef, useState, RefObject } from 'react';
interface UseIntersectionObserverOptions extends IntersectionObserverInit {
triggerOnce?: boolean;
}
interface UseIntersectionObserverReturn {
ref: RefObject<HTMLElement>;
isIntersecting: boolean;
entry: IntersectionObserverEntry | null;
}
export function useIntersectionObserver(
options: UseIntersectionObserverOptions = {}
): UseIntersectionObserverReturn {
const { triggerOnce = false, ...observerOptions } = options;
const [isIntersecting, setIsIntersecting] = useState(false);
const [entry, setEntry] = useState<IntersectionObserverEntry | null>(null);
const elementRef = useRef<HTMLElement>(null);
useEffect(() => {
const element = elementRef.current;
if (!element) return;
const observer = new IntersectionObserver(([entry]) => {
setIsIntersecting(entry.isIntersecting);
setEntry(entry);
if (triggerOnce && entry.isIntersecting) {
observer.disconnect();
}
}, observerOptions);
observer.observe(element);
return () => {
observer.disconnect();
};
}, [triggerOnce, observerOptions.root, observerOptions.rootMargin, observerOptions.threshold]);
return { ref: elementRef, isIntersecting, entry };
}import { useRef } from 'react';
export function useIsFirstRender(): boolean {
const isFirst = useRef(true);
if (isFirst.current) {
isFirst.current = false;
return true;
}
return false;
}import { useEffect, useRef } from 'react';
export function usePrevious<T>(value: T): T | undefined {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}A React hook to throttle function calls, limiting execution frequency.
import { useEffect, useRef, useState } from 'react';
export function useThrottle<T>(value: T, delay: number): T {
const [throttledValue, setThrottledValue] = useState(value);
const lastRan = useRef(Date.now());
useEffect(() => {
const handler = setTimeout(() => {
if (Date.now() - lastRan.current >= delay) {
setThrottledValue(value);
lastRan.current = Date.now();
}
}, delay - (Date.now() - lastRan.current));
return () => clearTimeout(handler);
}, [value, delay]);
return throttledValue;
}Track window dimensions for responsive design and layout calculations.
import { useState, useEffect } from 'react';
interface WindowSize {
width: number;
height: number;
}
export function useWindowSize(): WindowSize {
const [windowSize, setWindowSize] = useState<WindowSize>({
width: 0,
height: 0,
});
useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
// Set initial size
handleResize();
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowSize;
}React hook to track CSS media query matches for responsive design.
import { useState, useEffect } from 'react';
export function useMediaQuery(query: string): boolean {
const [matches, setMatches] = useState(false);
useEffect(() => {
const media = window.matchMedia(query);
// Set initial value
if (media.matches !== matches) {
setMatches(media.matches);
}
// Create listener
const listener = (event: MediaQueryListEvent) => {
setMatches(event.matches);
};
// Modern browsers
if (media.addEventListener) {
media.addEventListener('change', listener);
return () => media.removeEventListener('change', listener);
} else {
// Fallback for older browsers
media.addListener(listener);
return () => media.removeListener(listener);
}
}, [matches, query]);
return matches;
}A custom React hook for fetching data with loading and error states.
import { useState, useEffect } from 'react';
interface UseFetchResult<T> {
data: T | null;
loading: boolean;
error: Error | null;
refetch: () => void;
}
export function useFetch<T>(
url: string,
options?: RequestInit
): UseFetchResult<T> {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
const fetchData = async () => {
try {
setLoading(true);
setError(null);
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (err) {
setError(err instanceof Error ? err : new Error('Unknown error'));
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchData();
}, [url]);
return { data, loading, error, refetch: fetchData };
}Truncate long strings with ellipsis, useful for previews and card layouts.
export function truncateString(
str: string,
maxLength: number,
suffix: string = '...'
): string {
if (str.length <= maxLength) {
return str;
}
return str.slice(0, maxLength - suffix.length) + suffix;
}Detect clicks outside a specific element, useful for closing modals and dropdowns.
import { useEffect, RefObject } from 'react';
export function useClickOutside<T extends HTMLElement = HTMLElement>(
ref: RefObject<T>,
handler: (event: MouseEvent | TouchEvent) => void
): void {
useEffect(() => {
const listener = (event: MouseEvent | TouchEvent) => {
const el = ref?.current;
if (!el || el.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]);
}A React hook to persist state in localStorage with automatic synchronization.
import { useState, useEffect } from 'react';
export function useLocalStorage<T>(
key: string,
initialValue: T
): [T, (value: T | ((val: T) => T)) => void] {
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];
}import { useCallback, useState } from 'react';
export function useToggle(initial = false): [boolean, () => void] {
const [value, setValue] = useState(initial);
const toggle = useCallback(() => setValue(v => !v), []);
return [value, toggle];
}import { useEffect, useRef } from 'react';
export function useIsMounted() {
const isMounted = useRef(false);
useEffect(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
return isMounted;
}import { useEffect, useState } from 'react';
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
}A simple utility function to narrow unknown types in TypeScript.
export function isString(value: unknown): value is string {
return typeof value === 'string';
}export function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}A utility function to ensure exhaustive checks in switch statements.
export function assertNever(x: never): never {
throw new Error("Unexpected object: " + x);
}