Volver al inicio

Cómo usar React Hooks: Guía completa con ejemplos

Esta guía completa enseña a los desarrolladores cómo usar los hooks de React de manera efectiva en aplicaciones modernas de React. Cubre hooks esenciales incorporados como useState y useEffect, explica las reglas de los hooks, proporciona técnicas de optimización de rendimiento con useMemo y useCallback, y demuestra la creación de hooks personalizados con ejemplos de código prácticos.

Tutorial de React Hooks: Domina Estado y Efectos en 2026
Advertisement 728x90

Cómo Usar React Hooks: Una Guía Completa con Ejemplos

Cómo Usar React Hooks: Una Guía Completa con Ejemplos

Cuando React 16.8 introdujo los Hooks a principios de 2019, cambió fundamentalmente la forma en que los desarrolladores construyen aplicaciones React al permitir que los componentes funcionales gestionen estado, efectos secundarios y contexto sin necesidad de escribir componentes de clase. Comprender cómo usar React hooks de manera efectiva es ahora esencial para cualquier desarrollador moderno de React, ya que los Hooks se han convertido en "la única forma en que se escribe la mayor parte del código React". Esta guía te explicará los Hooks integrados esenciales, las reglas que los rigen y te proporcionará ejemplos prácticos que puedes usar de inmediato.

Lo Que Aprenderás

Al final de esta guía, usarás con confianza los Hooks principales de React —useState, useEffect, useContext, useRef, useReducer, useMemo y useCallback— en tus propios proyectos. Entenderás cuándo elegir un Hook sobre otro, cómo evitar errores comunes como renderizados innecesarios y cómo extraer lógica reutilizable en Hooks personalizados. La conclusión más importante es que los Hooks son solo funciones: aprender a componerlos es la clave para dominar React.

Google AdInline article slot

Comprendiendo las Reglas de los Hooks

Antes de sumergirte en Hooks individuales, debes entender dos reglas no negociables impuestas por el paquete eslint-plugin-react-hooks:

  1. Solo llama a los Hooks en el nivel superior. Nunca llames a Hooks dentro de bucles, condiciones o funciones anidadas. React depende del orden en que se llaman los Hooks para preservar el estado entre renderizados; si el orden cambia, React no puede asociar correctamente el estado con su Hook.

  2. Solo llama a los Hooks desde funciones de React. Solo puedes llamar a Hooks desde componentes funcionales o desde otros Hooks personalizados. Una función JavaScript normal no puede llamar a useState o useEffect.

    Google AdInline article slot

De la segunda regla surge una convención: cualquier función que llame a Hooks debe comenzar con use (por ejemplo, useCustomHook). El linter usa este prefijo para aplicar las reglas correctamente.

Los Hooks Más Esenciales Que Usarás a Diario

useState: Gestionando el Estado del Componente

El Hook useState es el más fundamental, ya que te permite agregar estado a componentes funcionales. Devuelve un array con dos elementos: el valor actual del estado y una función para actualizarlo.

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // El estado inicial es 0
  
  return (
    <button onClick={() => setCount(count + 1)}>
      Clickeado {count} veces
    </button>
  );
}

Cuando actualices el estado basándote en el valor anterior, usa la forma de actualización funcional para evitar condiciones de carrera, especialmente con el agrupamiento automático de React:

Google AdInline article slot
// Seguro: usa el valor de estado anterior
setCount(prevCount => prevCount + 1);

// También seguro para objetos: extiende el estado anterior
setUser(prevUser => ({ ...prevUser, name: 'Jane' }));

Si calcular el estado inicial es costoso, pasa una función en lugar de un valor; React la ejecutará solo en el renderizado inicial:

const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props);
  return initialState;
});

useEffect: Manejando Efectos Secundarios

El Hook useEffect te permite realizar efectos secundarios en componentes funcionales, como obtener datos, configurar suscripciones o modificar manualmente el DOM. Por defecto, los efectos se ejecutan después de cada renderizado completo, pero puedes controlar cuándo se disparan usando el array de dependencias.

import { useEffect, useState } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // Este efecto se ejecuta después de que el componente se monta y cuando userId cambia
    fetchUser(userId).then(data => setUser(data));
    
    // Función de limpieza opcional que se ejecuta antes del siguiente efecto y al desmontar
    return () => {
      // Cancela cualquier solicitud pendiente o limpia suscripciones
    };
  }, [userId]); // Array de dependencias: se vuelve a ejecutar solo cuando userId cambia

  return <div>{user?.name}</div>;
}

Patrones clave para useEffect:

  • Array de dependencias vacío []: El efecto se ejecuta una vez después del renderizado inicial (montaje).
  • Sin array de dependencias: El efecto se ejecuta después de cada renderizado (rara vez es lo que quieres).
  • Función de limpieza: Previene fugas de memoria limpiando suscripciones, temporizadores o solicitudes de red pendientes.

Advertencia importante: No todo cambio de estado requiere un efecto. Si puedes calcular un valor durante el renderizado, hazlo directamente en lugar de usar useEffect:

// ❌ Efecto innecesario
const [fullName, setFullName] = useState('');
useEffect(() => {
  setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);

// ✅ Calcula directamente durante el renderizado
const fullName = `${firstName} ${lastName}`;

useContext: Consumiendo Contexto Sin Prop Drilling

El Hook useContext te permite leer valores del Contexto de React sin envolver tu componente en un componente Consumer:

import { useContext } from 'react';

// Crea un contexto
const ThemeContext = React.createContext('light');

function ThemedButton() {
  // Lee el valor del contexto directamente
  const theme = useContext(ThemeContext);
  return <button className={theme}>Haz clic</button>;
}

Cuando el valor del proveedor de contexto cambia, cualquier componente que use useContext se vuelve a renderizar automáticamente.

useRef: Referenciando Valores Que No Provocan Renderizados

El Hook useRef crea un objeto ref mutable cuya propiedad .current persiste entre renderizados. A diferencia del estado, actualizar una ref no provoca un nuevo renderizado. Esto hace que las refs sean ideales para:

  • Almacenar referencias a elementos del DOM
  • Mantener un registro de IDs de temporizadores
  • Persistir valores que no deberían desencadenar actualizaciones de la interfaz de usuario
import { useRef, useEffect } from 'react';

function TextInput() {
  const inputRef = useRef(null);

  useEffect(() => {
    // Enfoca el input después de que el componente se monta
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} type="text" />;
}

useReducer: Gestionando Lógica de Estado Compleja

Para estados que involucran múltiples subvalores o transiciones complejas, useReducer suele ser preferible a useState. Acepta una función reductora y un estado inicial, y devuelve el estado actual y una función dispatch:

import { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return { count: action.payload };
    default:
      return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'reset', payload: 0 })}>Reset</button>
    </>
  );
}

Hooks de Optimización de Rendimiento

useMemo: Almacenando en Caché Cálculos Costosos

useMemo almacena en caché el resultado de un cálculo y solo lo recalcula cuando las dependencias cambian:

import { useMemo } from 'react';

function TodoList({ todos, filter }) {
  // Solo recalcula cuando todos o filter cambian
  const filteredTodos = useMemo(() => {
    return todos.filter(todo => todo.status === filter);
  }, [todos, filter]);

  return (
    <ul>
      {filteredTodos.map(todo => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  );
}

useCallback: Memorizando Referencias de Funciones

useCallback devuelve una versión memorizada de una función callback que solo cambia si las dependencias cambian. Esto es particularmente útil al pasar callbacks a componentes hijos optimizados que dependen de la igualdad de referencia para evitar renderizados innecesarios:

import { useCallback } from 'react';

function ParentComponent() {
  const handleClick = useCallback(() => {
    console.log('Botón clickeado');
  }, []); // La referencia de la función se mantiene estable entre renderizados

  return <ChildButton onClick={handleClick} />;
}

Hooks Personalizados: Reutilizando Lógica Entre Componentes

El verdadero poder de los Hooks surge cuando creas Hooks personalizados para extraer y reutilizar lógica con estado. Un Hook personalizado es simplemente una función JavaScript cuyo nombre comienza con use y que puede llamar a otros Hooks.

Ejemplo: useLocalStorage

Este Hook personalizado sincroniza el estado con localStorage, persistiendo datos entre recargas de página:

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    if (typeof window === 'undefined') return initialValue;
    const stored = localStorage.getItem(key);
    return stored !== null ? JSON.parse(stored) : initialValue;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

// Uso
function ThemeToggle() {
  const [theme, setTheme] = useLocalStorage('theme', 'light');
  return (
    <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      Cambiar a modo {theme === 'light' ? 'oscuro' : 'claro'}
    </button>
  );
}

Ejemplo: useMediaQuery

Este Hook te permite renderizar componentes condicionalmente basándote en consultas de medios CSS, como la preferencia del usuario por movimiento reducido:

import { useState, useEffect } from 'react';

function useMediaQuery(query) {
  const [matches, setMatches] = useState(() => {
    if (typeof window === 'undefined') return false;
    return window.matchMedia(query).matches;
  });

  useEffect(() => {
    const mediaQueryList = window.matchMedia(query);
    const onChange = (event) => setMatches(event.matches);
    mediaQueryList.addEventListener('change', onChange);
    return () => mediaQueryList.removeEventListener('change', onChange);
  }, [query]);

  return matches;
}

// Uso
function MotionAwareComponent() {
  const prefersReducedMotion = useMediaQuery('(prefers-reduced-motion: reduce)');
  return prefersReducedMotion ? <StaticHero /> : <AnimatedHero />;
}

React 19: Nuevos Hooks para Formularios y Datos Asíncronos

React 19 (lanzado en diciembre de 2024) introdujo varios Hooks nuevos diseñados para simplificar el manejo de formularios y operaciones asíncronas.

useActionState: Simplificando el Envío de Formularios

useActionState gestiona el estado de envío de formularios, devolviendo el último resultado, una función de acción y un indicador de pendiente:

import { useActionState } from 'react';

async function subscribeAction(prevState, formData) {
  const email = formData.get('email');
  try {
    await subscribe(email);
    return { ok: true };
  } catch (error) {
    return { ok: false, error: error.message };
  }
}

function NewsletterForm() {
  const [state, formAction, isPending] = useActionState(
    subscribeAction,
    { ok: false }
  );

  return (
    <form action={formAction}>
      <input name="email" type="email" required />
      <button type="submit" disabled={isPending}>
        {isPending ? 'Suscribiendo...' : 'Suscribirse'}
      </button>
      {state.ok && <p>¡Estás suscrito!</p>}
      {state.error && <p style={{ color: 'red' }}>{state.error}</p>}
    </form>
  );
}

useFormStatus: Accediendo al Estado del Formulario Padre

useFormStatus permite a los componentes anidados saber si su formulario padre se está enviando:

import { useFormStatus } from 'react';

function SubmitButton() {
  const { pending } = useFormStatus();
  return (
    <button type="submit" disabled={pending}>
      {pending ? 'Guardando...' : 'Guardar'}
    </button>
  );
}

Integración con Redux: El Hook useSelector

Cuando usas Redux con React, el Hook useSelector es la forma moderna y recomendada de acceder al estado del store de Redux. Reemplaza el antiguo componente de orden superior connect y funciona mejor con TypeScript.

import { useSelector, useDispatch } from 'react-redux';

function CounterComponent() {
  // Extrae datos específicos del store de Redux
  const count = useSelector((state) => state.counter.value);
  const dispatch = useDispatch();

  return (
    <div>
      <span>{count}</span>
      <button onClick={() => dispatch(increment())}>Incrementar</button>
    </div>
  );
}

Importante: useSelector usa igualdad de referencia estricta === por defecto. Devolver un nuevo objeto cada vez forzará renderizados. Usa selectores memorizados o llama a useSelector varias veces para campos individuales para optimizar el rendimiento:

// ❌ Esto provoca renderizados en cada acción
const { count, user } = useSelector((state) => ({
  count: state.count,
  user: state.user
}));

// ✅ Llama a useSelector para cada campo
const count = useSelector((state) => state.count);
const user = useSelector((state) => state.user);

Fuentes

  • Documentación Oficial de React: Hooks Integrados de React
  • Documentación Oficial de React: Referencia de la API de Hooks
  • Documentación de React Redux: API de Hooks
  • Patterns.dev: Patrón de Hooks
  • Documentación Oficial de React: Usando el Hook de Estado

— Editorial Team

Advertisement 728x90

Leer después