React: Creando Custom Hooks Reutilizables
25 de diciembre de 2025
Osman Jimenez
React Hooks JavaScript
Custom Hooks en React
Los custom hooks permiten reutilizar lógica entre componentes. Aprende a crear hooks útiles y reutilizables.
useLocalStorage
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
}
// Uso
const [name, setName] = useLocalStorage('name', 'John');useFetch
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const json = await response.json();
setData(json);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// Uso
const { data, loading, error } = useFetch('/api/users');useDebounce
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
}
// Uso
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearch = useDebounce(searchTerm, 500);
useEffect(() => {
if (debouncedSearch) {
searchAPI(debouncedSearch);
}
}, [debouncedSearch]);useMediaQuery
function useMediaQuery(query) {
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;
}
// Uso
const isMobile = useMediaQuery('(max-width: 768px)');useOnClickOutside
function useOnClickOutside(ref, handler) {
useEffect(() => {
const listener = (event) => {
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler(event);
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
}, [ref, handler]);
}
// Uso
const ref = useRef();
useOnClickOutside(ref, () => setIsOpen(false));useIntersectionObserver
function useIntersectionObserver(ref, options) {
const [isIntersecting, setIntersecting] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
setIntersecting(entry.isIntersecting);
}, options);
if (ref.current) {
observer.observe(ref.current);
}
return () => {
observer.disconnect();
};
}, [ref, options]);
return isIntersecting;
}
// Uso - Lazy loading
const ref = useRef();
const isVisible = useIntersectionObserver(ref, { threshold: 0.5 });usePrevious
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
// Uso
const [count, setCount] = useState(0);
const prevCount = usePrevious(count);useToggle
function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = useCallback(() => {
setValue(v => !v);
}, []);
return [value, toggle];
}
// Uso
const [isOpen, toggleOpen] = useToggle();Mejores Prácticas
- Prefijo use: Siempre nombra hooks con 'use'
- Reglas de Hooks: Solo llama hooks en el top level
- Dependencies: Incluye todas las dependencias en useEffect
- Cleanup: Retorna función de limpieza cuando sea necesario
- Memoización: Usa useCallback y useMemo apropiadamente
Conclusión
Los custom hooks son una forma poderosa de compartir lógica entre componentes. Crea una librería de hooks reutilizables para tu proyecto y aumenta tu productividad.