Custom Hook Beispiele
useMousePosition
Trackt die Mausposition — Event Listener Setup & Cleanup Pattern.
function useMousePosition() {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const handler = (e) => {
setPosition({ x: e.clientX, y: e.clientY });
};
window.addEventListener('mousemove', handler);
return () => window.removeEventListener('mousemove', handler);
}, []);
return position;
}
// Usage
const { x, y } = useMousePosition();
useFetch
Data Fetching mit Loading, Error & Cleanup.
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 isMounted = true; // Prevent state update on unmount
async function fetchData() {
try {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
if (isMounted) {
setData(json);
setLoading(false);
}
} catch (err) {
if (isMounted) {
setError(err.message);
setLoading(false);
}
}
}
fetchData();
return () => { isMounted = false; };
}, [url]);
return { data, loading, error };
}
// Usage
const { data, loading, error } = useFetch('/api/users');
useLocalStorage
State persistieren — synct automatisch mit localStorage.
function useLocalStorage<T>(key: string, initial: T) {
const [value, setValue] = useState<T>(() => {
if (typeof window === 'undefined') return initial;
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initial;
} catch {
return initial;
}
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue] as const;
}
// Usage
const [theme, setTheme] = useLocalStorage('theme', 'dark');
useDebounce
Verzögert einen Wert — perfekt für Search Inputs.
function useDebounce<T>(value: T, delay: number) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// Usage
const [search, setSearch] = useState('');
const debouncedSearch = useDebounce(search, 300);
useEffect(() => {
// API call nur wenn User aufhört zu tippen
fetchResults(debouncedSearch);
}, [debouncedSearch]);
useOnClickOutside
Callback wenn außerhalb eines Elements geklickt wird — für Dropdowns, Modals.
function useOnClickOutside(
ref: RefObject<HTMLElement>,
handler: () => void
) {
useEffect(() => {
const listener = (e: MouseEvent) => {
if (!ref.current || ref.current.contains(e.target as Node)) {
return;
}
handler();
};
document.addEventListener('mousedown', listener);
return () => document.removeEventListener('mousedown', listener);
}, [ref, handler]);
}
// Usage
const dropdownRef = useRef(null);
useOnClickOutside(dropdownRef, () => setIsOpen(false));