React Hooks — qué son, hooks principales y reglas de uso

Autor: IT Sectr Publicado: 2026-07-04 Tiempo de lectura: 10 min

React Hooks son funciones que permiten usar estado, efectos, contexto y otras características de React en componentes funcionales, sin escribir clases. Introducidos en React 16.8, los hooks cambiaron radicalmente el enfoque de desarrollo, reemplazando patrones complejos como HOC y render props. Según React, 2024, existen 15 hooks incorporados que cubren todos los escenarios de gestión de componentes.

Puntos clave

  • Hooks — funciones para conectar funcionalidades de React a componentes funcionales sin extends Component.
  • useState — el hook básico para gestionar el estado, devuelve un valor y un setter.
  • useEffect — para efectos secundarios: peticiones API, suscripciones, temporizadores, manipulaciones del DOM.
  • useContext — para acceder al contexto de React sin envoltorios Consumer ni static contextType.
  • Reglas de los hooks — llamar solo en el nivel superior y solo dentro de componentes funcionales o hooks personalizados.

¿Qué son los React Hooks?

React Hooks son un conjunto de funciones integradas en React que permiten “conectarse” a los mecanismos internos del framework sin crear clases. Antes de React 16.8, los componentes funcionales solo podían aceptar props y devolver JSX — cualquier lógica compleja requería un componente de clase.

El problema de los componentes de clase es la división de la lógica relacionada. El código relacionado con una misma entidad (por ejemplo, una suscripción a WebSocket) se dividía forzosamente entre componentDidMount, componentDidUpdate y componentWillUnmount. Los hooks resuelven esto: toda la lógica se agrupa en un solo useEffect.

El segundo problema es la reutilización de la lógica. Para reutilizar la lógica de estado entre componentes de clase, había que aplicar HOC (Componentes de Orden Superior) o render props — ambos patrones creaban anidamiento adicional en el árbol de componentes. Los hooks personalizados resuelven esto sin anidamiento.

useState — Gestión del estado

useState es el hook más básico. Recibe un valor inicial y devuelve una tupla: el valor actual y una función para actualizarlo. A diferencia de this.setState en las clases, useState no fusiona objetos — el nuevo estado reemplaza completamente al anterior para una llamada específica de useState.

js
import React, { useState } from 'react';

function Form() {
  const [text, setText] = useState('');
  const [submitting, setSubmitting] = useState(false);

  async function handleSubmit() {
    setSubmitting(true);
    await fetch('/api/submit', {
      method: 'POST',
      body: JSON.stringify({ text })
    });
    setSubmitting(false);
  }

  return (
    <div>
      <input
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <button onClick={handleSubmit}
        disabled={submitting}>
        {submitting ? 'Saving...' : 'Submit'}
      </button>
    </div>
  );
}

Forma funcional de setState

El setter de useState puede aceptar una función que recibe el valor anterior y devuelve uno nuevo. La forma funcional es obligatoria cuando el nuevo estado se calcula a partir del anterior y es posible que haya llamadas setState agrupadas — cada llamada recibirá el valor anterior actual.

useEffect — Efectos secundarios y ciclo de vida

useEffect es un hook para realizar efectos secundarios en componentes funcionales. Recibe dos argumentos: una función de efecto y un array de dependencias. React ejecuta el efecto después de cada renderizado, pero cuando se especifican dependencias — solo cuando alguna de ellas cambia.

Un array de dependencias vacío [] significa que el efecto se ejecuta una vez después del primer renderizado (análogo a componentDidMount). Devolver una función desde el efecto es una limpieza que se ejecuta al desmontar (análogo a componentWillUnmount) y antes de volver a ejecutar el efecto.

js
import React, { useState, useEffect } from 'react';

function ChatRoom({ roomId }) {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const socket = new WebSocket(`wss://chat/${roomId}`);

    socket.onmessage = (event) => {
      setMessages(prev => [...prev, JSON.parse(event.data)]);
    };

    // Cierre de limpieza - cerrar socket
    return () => socket.close();
  }, [roomId]);

  return <ul>
    {messages.map((msg, i) =>
      <li key={i}>{msg.text}</li>
    )}
  </ul>;
}

Las dependencias de useEffect son la única conexión entre el efecto y el mundo exterior. Si el efecto usa una variable de props o estado, debe estar en el array de dependencias. Ignorar esta regla provoca errores con cierres obsoletos (stale closures).

useContext — Acceso al contexto

useContext es un hook para leer valores del contexto. Recibe un objeto de contexto creado por React.createContext y devuelve el valor actual. Si el contexto cambia, el componente se vuelve a renderizar automáticamente con el nuevo valor.

Antes de useContext, acceder al contexto en componentes funcionales requería envolver en Context.Consumer, lo que creaba anidamiento. useContext elimina completamente Consumer — basta con llamar al hook en cualquier lugar del componente funcional.

js
import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('claro');

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return <button
    className={`btn btn-${theme}`}
  >
    {theme === 'dark' ? 'moon' : '☀️'}
  </button>;
}

useContext no es un reemplazo de Redux ni del estado global. React recomienda usar el contexto para valores que cambian con poca frecuencia — tema, configuración regional, estado de autenticación. Para datos que se actualizan con frecuencia, cada re-renderizado recalculará todos los consumidores del contexto, lo que puede reducir el rendimiento.

useReducer — Lógica de estado compleja

useReducer es una alternativa a useState para estados con lógica de actualización compleja. Recibe una función reductora y un estado inicial, devuelve el estado actual y una función dispatch. El reductor recibe el estado actual y una acción, devuelve un nuevo estado — una función pura sin efectos secundarios.

useReducer es especialmente útil cuando múltiples acciones (set, reset, increment, addItem) gestionan un mismo estado. En lugar de múltiples useState con diferentes setters — un solo reductor con tipos de acción claros. Esto hace que la lógica sea predecible y fácil de probar.

js
import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + 1 };
    case 'setStep':
      return { ...state, step: action.step };
    case 'reset':
      return { count: 0, step: 1 };
    default:
      throw new Error('Unknown action: ' + action.type);
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, {
    count: 0,
    step: 1
  });

  return (
    <>
      <p>Count: {state.count}</p>
      <button
        onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button
        onClick={() => dispatch({ type: 'reset' })}>Reset</button>
    </>
  );
}

useRef, useMemo, useCallback — Optimización

useRef crea un objeto mutable que persiste entre renderizados. Cambiar current no provoca un re-renderizado. Los usos principales son acceder a elementos del DOM y almacenar valores mutables (temporizadores, valores anteriores, instancias de librerías).

useMemo memoiza el resultado de una función. Recalcula el valor solo cuando cambia una dependencia. Úselo para cálculos costosos — filtrado de arrays grandes, ordenación, formato de datos. useCallback es un caso especial de useMemo para memoizar funciones.

js
import React, { useRef, useMemo, useCallback } from 'react';

function SearchPage({ items, query, onItemSelect }) {
  const inputRef = useRef(null);

  // Autoenfoque al montar
  useEffect(() => {
    inputRef.current?.focus();
  }, []);

  // Memoizar resultado filtrado
  const filtered = useMemo(() => {
    return items.filter(item =>
      item.name.toLowerCase()
        .includes(query.toLowerCase())
    );
  }, [items, query]);

  // Memoizar callback
  const handleSelect = useCallback((id) => {
    onItemSelect(id);
  }, [onItemSelect]);

  return (
    <div>
      <input ref={inputRef}
        value={query}
        onChange={e => setQuery(e.target.value)}
      />
      <ul>
        {filtered.map(item =>
          <li key={item.id}>
            <button
              onClick={() => handleSelect(item.id)}>
              {item.name}
            </button>
          </li>
        )}
      </ul>
    </div>
  );
}

Una regla importante: useRef, useMemo y useCallback son herramientas de optimización, no construcciones obligatorias. No envuelva todo en useMemo — mida el rendimiento primero. La optimización prematura complica el código. React renderiza componentes rápidamente; useMemo solo es necesario cuando los cálculos son realmente costosos (O(n²) o superior).

Reglas de los hooks y errores comunes

React introdujo dos reglas estrictas para los hooks. Primera: llame a los hooks solo en el nivel superior — no dentro de condiciones, bucles o funciones anidadas. Segunda: llame a los hooks solo desde componentes funcionales de React o hooks personalizados. El plugin de ESLint eslint-plugin-react-hooks verifica automáticamente ambas reglas.

El error más común es violar el orden de llamada de los hooks. React depende del orden de llamada de los hooks entre renderizados. Si un hook está dentro de una condición y no se ejecuta en un renderizado, todos los hooks posteriores se desplazan, causando errores.

ErrorQué sucedeSolución
Hook en una condiciónEl orden de los hooks se rompeTraslade la lógica de la condición dentro del hook
Stale closureEl efecto usa un valor antiguoAñada todas las dependencias al array
Bucle infinitouseEffect sin dependencias cambia el estadoEspecifique dependencias o use useReducer
Mutación de ref en renderEfecto secundario en el cuerpo de la funciónMueva las mutaciones a useEffect

El segundo error común es stale closure en useEffect. Si el efecto usa una variable no especificada en las dependencias, el efecto “captura” su valor en el momento de la creación del cierre. La solución es incluir siempre todas las variables usadas en el array de dependencias. Si hay demasiadas dependencias, considere dividir el efecto en varios.

Preguntas frecuentes

¿Por qué los hooks no se pueden llamar dentro de condiciones?

React depende del orden de llamada de los hooks entre renderizados. Si un hook se llama dentro de una condición y no se ejecuta en un renderizado, todos los hooks posteriores se desplazan — su estado se mezcla. La regla de ESLint hooks/exhaustive-deps advierte sobre esto.

¿Cuál es la diferencia entre useEffect y useLayoutEffect?

useLayoutEffect es síncrono y se ejecuta antes de que el navegador pinte los cambios. useEffect es asíncrono — después del pintado. Use useLayoutEffect solo cuando necesite medir o cambiar el DOM antes de que el usuario vea los cambios (posición de popover, restauración de scroll).

¿Cómo cancelar una petición fetch al desmontar?

Use AbortController dentro de useEffect. Cree un controller, pase la señal a fetch y llame a controller.abort() en la función de limpieza. Para navegadores antiguos, use un flag cancelled: return () => { cancelled = true; } con una verificación antes de setState.

¿Qué es un hook personalizado y cuándo crearlo?

Un hook personalizado es una función de JavaScript con el prefijo use que utiliza hooks incorporados. Créelo cuando la misma lógica con hooks se repite en dos o más componentes. Ejemplos: useDebounce, useLocalStorage, useMediaQuery. Los hooks personalizados reemplazan a HOC y render props.

¿Por qué useEffect se ejecuta dos veces en Strict Mode?

En Strict Mode, React monta y desmonta intencionadamente el componente dos veces en desarrollo para encontrar errores con efectos no limpiados. Si la limpieza está escrita correctamente, la doble llamada no causa problemas. Esto no ocurre en modo de producción.

Resumen

  • React Hooks — funciones para usar estado, efectos y contexto en componentes funcionales, reemplazando las clases.
  • useState — hook básico para estado local con un setter funcional para actualizaciones seguras.
  • useEffect — hook universal para efectos secundarios con array de dependencias y función de limpieza.
  • useContext — acceso directo al contexto de React sin envoltorios Consumer ni anidamiento extra.
  • useReducer — para lógica de estado compleja con tipos de acción, una alternativa a Redux dentro de un solo componente.
  • useRef, useMemo, useCallback — herramientas de optimización: referencias al DOM, memoización de valores y callbacks.
  • Regla del nivel superior — restricción estricta de llamar a hooks fuera de condiciones, bucles y funciones anidadas.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también