0Pricing
Frontend Academy · Lección

Hooks personalizados: extraer lógica reutilizable

Traslade la lógica con estado a funciones personalizadas use* para compartir comportamiento entre componentes sin duplicar código ni elevar el estado.

Hooks personalizados: extraer lógica reutilizable es una lección gratuita de Frontend Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Frontend Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Frontend Academy incluye 4 lecciones en total.

¿Qué son los hooks personalizados?

Un hook personalizado es una función de JavaScript cuyo nombre comienza por use y que llama internamente a otros hooks. Los hooks personalizados permiten extraer lógica con estado para que varios componentes la compartan sin copiarla y pegarla.

Extraer lógica a un hook personalizado

Identifique la lógica duplicada entre componentes (obtención de datos, carga y errores; tamaño de la ventana; almacenamiento local) y muévala a un hook personalizado.

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handler = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handler);
    return () => window.removeEventListener('resize', handler);
  }, []);

  return width;
}

// Usage:
const width = useWindowWidth();
const isMobile = width < 768;

useFetch: hook para obtener datos

Un hook reutilizable para obtener datos que cualquier componente puede usar para cargar datos desde una URL.

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(() => {
    const controller = new AbortController();
    async function load() {
      try {
        const res = await fetch(url, { signal: controller.signal });
        if (!res.ok) throw new Error(`${res.status}`);
        setData(await res.json());
      } catch (err) {
        if ((err as DOMException).name !== 'AbortError')
          setError((err as Error).message);
      } finally { setLoading(false); }
    }
    load();
    return () => controller.abort();
  }, [url]);

  return { data, loading, error };
}

Hook useLocalStorage

Un hook personalizado que sincroniza un valor con localStorage y lo mantiene sincronizado entre pestañas mediante el evento storage.

function useLocalStorage<T>(key: string, initialValue: T) {
  const [value, setValue] = useState<T>(() => {
    const stored = localStorage.getItem(key);
    return stored ? JSON.parse(stored) : initialValue;
  });

  const set = useCallback((newValue: T) => {
    setValue(newValue);
    localStorage.setItem(key, JSON.stringify(newValue));
  }, [key]);

  return [value, set] as const;
}

Los hooks personalizados comparten lógica, no estado

Cada componente que llama a un hook personalizado obtiene su propio estado independiente. Los hooks no son singletons: son llamadas a funciones que crean instancias de estado aisladas.

Convenciones de nomenclatura

Los nombres de los hooks personalizados deben comenzar por use. Esto se aplica mediante las reglas de linting de react-hooks de ESLint, que garantizan que los hooks se llamen en el nivel superior y en el orden correcto.

Devolver varios valores

Los hooks personalizados suelen devolver un objeto (con valores con nombre) o una tupla (como useState). Las tuplas permiten desestructurar con nombres personalizados; los objetos se documentan por sí mismos.

// Tuple (like useState):
const [value, setValue] = useLocalStorage('key', 0);

// Object (more descriptive):
const { data, loading, error, refetch } = useFetch('/api/users');

Hook useDebounce

Aplique debounce a un valor: actualícelo solo después de que el usuario deje de escribir durante un retraso especificado.

function useDebounce<T>(value: T, delay: number): T {
  const [debounced, setDebounced] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebounced(value), delay);
    return () => clearTimeout(timer);
  }, [value, delay]);

  return debounced;
}

// Usage:
const debouncedSearch = useDebounce(searchTerm, 300);
useEffect(() => { search(debouncedSearch); }, [debouncedSearch]);

Hook useMediaQuery

Envuelve window.matchMedia en un hook para leer reactivamente los resultados de una consulta de medios CSS.

function useMediaQuery(query: string): boolean {
  const [matches, setMatches] = useState(() => window.matchMedia(query).matches);

  useEffect(() => {
    const mq = window.matchMedia(query);
    const handler = (e: MediaQueryListEvent) => setMatches(e.matches);
    mq.addEventListener('change', handler);
    return () => mq.removeEventListener('change', handler);
  }, [query]);

  return matches;
}

Probar hooks personalizados

Use la utilidad renderHook() de @testing-library/react para probar hooks personalizados de forma aislada sin envolverlos en un componente.

import { renderHook, act } from '@testing-library/react';

test('useCounter increments', () => {
  const { result } = renderHook(() => useCounter(0));
  expect(result.current.count).toBe(0);
  act(() => result.current.increment());
  expect(result.current.count).toBe(1);
});

Bibliotecas de hooks publicadas

Las bibliotecas de hooks de la comunidad proporcionan cientos de hooks probados: @uidotdev/usehooks, react-use, usehooks-ts. Antes de escribir un hook personalizado, compruebe si ya existe una versión bien probada.

Comprobación rápida

¿Qué ocurre con el estado dentro de un hook personalizado cuando lo llaman dos componentes diferentes?

Recapitulación: hooks personalizados

Los hooks personalizados extraen lógica con estado para reutilizarla. Asígneles nombres con el prefijo use. Cada componente que llama al hook obtiene un estado independiente. Devuelven objetos o tuplas. Patrones habituales: useFetch, useLocalStorage, useDebounce y useMediaQuery. Pruébelos con renderHook(). Consulte las bibliotecas de la comunidad antes de escribir uno desde cero.

Preguntas frecuentes

¿La lección «Hooks personalizados: extraer lógica reutilizable» es gratis?

Sí — el texto completo de «Hooks personalizados: extraer lógica reutilizable» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Frontend Academy, actualiza a CoddyKit PRO. El curso de Frontend Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Hooks personalizados: extraer lógica reutilizable»?

Traslade la lógica con estado a funciones personalizadas use* para compartir comportamiento entre componentes sin duplicar código ni elevar el estado. Practicas Frontend Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Frontend Academy?

No se requiere experiencia previa. Frontend Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Hooks personalizados: extraer lógica reutilizable»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Frontend Academy?

Sí. Cada lección de Frontend Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. useContext para el estado global
  2. useReducer para estados complejos
  3. useMemo y useCallback para mejorar el rendimiento
  4. Hooks personalizados: extraer lógica reutilizable
← Volver a Frontend Academy