certmundo.
es‑mx

6 min de lectura

¿Cómo usar el estado con el hook useState?

El hook useState permite que un componente React recuerde y actualice información sin recargar la página.

Cuando un usuario hace clic en un botón o escribe en un campo, la interfaz necesita cambiar. useState es la herramienta que hace posible ese cambio.


Qué es el estado en React

El estado es información que puede cambiar con el tiempo dentro de un componente.

A diferencia de las props, que vienen del componente padre y son de solo lectura, el estado es privado y lo controla el propio componente. Piensa en él como la memoria interna del componente.

Ejemplos de estado típico:

  • El número de artículos en un carrito de Liverpool
  • Si un menú está abierto o cerrado
  • El texto que el usuario escribe en un formulario
  • El precio total de una orden en Mercado Libre

Sintaxis de useState

useState se importa desde React y se llama dentro del cuerpo de un componente funcional.

Estructura básica:

import { useState } from 'react';

const [valor, setValor] = useState(valorInicial);

useState devuelve un arreglo con exactamente dos elementos:

Elemento Qué es Ejemplo
valor El estado actual 0, false, ""
setValor Función para actualizar el estado setValor(1)
valorInicial El valor con el que empieza 0, true, []

Convención de nombres: Siempre nombra la función de actualización con el prefijo set. Si el estado se llama cantidad, la función es setCantidad.


Ejemplo 1 — Contador simple

Este es el ejemplo más directo para entender useState.

import { useState } from 'react';

function ContadorProductos() {
  const [cantidad, setCantidad] = useState(0);

  return (
    <div>
      <p>Productos en carrito: {cantidad}</p>
      <button onClick={() => setCantidad(cantidad + 1)}>
        Agregar
      </button>
      <button onClick={() => setCantidad(cantidad - 1)}>
        Quitar
      </button>
    </div>
  );
}

¿Qué pasa aquí?

  • cantidad empieza en 0.
  • Cada clic en "Agregar" llama a setCantidad(cantidad + 1).
  • React actualiza la pantalla automáticamente con el nuevo valor.
  • El componente no se recarga: solo vuelve a renderizarse con el estado nuevo.

Resultado visible en pantalla:

Productos en carrito: 3
[Agregar] [Quitar]

Ejemplo 2 — Estado con booleano (mostrar/ocultar)

Un caso muy común en aplicaciones reales es mostrar u ocultar un elemento.

import { useState } from 'react';

function DetallePromocion() {
  const [visible, setVisible] = useState(false);

  return (
    <div>
      <button onClick={() => setVisible(!visible)}>
        {visible ? 'Ocultar promoción' : 'Ver promoción'}
      </button>
      {visible && (
        <p>¡20% de descuento en productos Bimbo esta semana!</p>
      )}
    </div>
  );
}

Puntos clave:

  • !visible invierte el valor booleano cada vez que se hace clic.
  • {visible && <p>...</p>} es renderizado condicional: solo muestra el párrafo cuando visible es true.
  • El texto del botón también cambia según el estado actual.

Ejemplo 3 — Formulario con estado (más complejo)

Este ejemplo simula un campo de búsqueda como el de FEMSA o Liverpool.

import { useState } from 'react';

function BuscadorProducto() {
  const [busqueda, setBusqueda] = useState('');
  const [precioFiltro, setPrecioFiltro] = useState(0);

  const handleBusqueda = (e) => {
    setBusqueda(e.target.value);
  };

  const handlePrecio = (e) => {
    setPrecioFiltro(Number(e.target.value));
  };

  return (
    <div>
      <input
        type="text"
        placeholder="Buscar producto..."
        value={busqueda}
        onChange={handleBusqueda}
      />
      <input
        type="number"
        placeholder="Precio máximo"
        value={precioFiltro}
        onChange={handlePrecio}
      />
      <p>Buscando: {busqueda}</p>
      <p>Precio máximo: ${precioFiltro.toLocaleString('es-MX')}</p>
    </div>
  );
}

¿Qué es un input controlado?

Cuando escribes value={busqueda} y onChange={handleBusqueda}, el input es controlado. Esto significa que React es quien tiene el control del valor, no el navegador. Es la forma recomendada de manejar formularios en React.

Flujo de datos en un input controlado:

  1. El usuario escribe una letra.
  2. Se dispara el evento onChange.
  3. setBusqueda actualiza el estado.
  4. React vuelve a renderizar el componente con el nuevo valor.
  5. El input muestra el valor actualizado.

Reglas importantes de useState

Regla 1 — Solo se llama en el nivel superior del componente.

Nunca llames useState dentro de un if, un for o una función anidada.

// ❌ Incorrecto
if (condicion) {
  const [valor, setValor] = useState(0);
}

// ✅ Correcto
const [valor, setValor] = useState(0);
if (condicion) {
  setValor(10);
}

Regla 2 — Cada llamada a useState maneja una sola pieza de estado.

Si necesitas tres datos independientes, usa tres llamadas a useState.

const [nombre, setNombre] = useState('');
const [precio, setPrecio] = useState(0);
const [activo, setActivo] = useState(true);

Regla 3 — No mutés el estado directamente.

Siempre usa la función set. Modificar el estado directamente no dispara el re-render.

// ❌ Incorrecto — no causa re-render
cantidad = cantidad + 1;

// ✅ Correcto
setCantidad(cantidad + 1);

Errores comunes

Error 1 — Olvidar los corchetes en la desestructuración.

// ❌ Incorrecto
const resultado = useState(0);
// resultado es un arreglo, no el valor

// ✅ Correcto
const [contador, setContador] = useState(0);

Error 2 — Usar el valor anterior directamente en operaciones acumulativas.

Cuando el nuevo estado depende del estado anterior, usa la forma funcional.

// ❌ Puede fallar en actualizaciones rápidas
setCantidad(cantidad + 1);

// ✅ Forma segura con función
setCantidad(prev => prev + 1);

Esto importa cuando el usuario hace clic muy rápido o cuando hay múltiples actualizaciones seguidas.

Error 3 — Esperar que el estado se actualice de inmediato.

Llamar a setCantidad no cambia cantidad en la misma línea. React programa el re-render para después.

setCantidad(5);
console.log(cantidad); // Sigue mostrando el valor anterior

Error 4 — Poner objetos grandes en un solo useState innecesariamente.

Si dos datos no cambian juntos, es mejor separarlos en dos estados independientes. Esto hace el código más fácil de leer y depurar.


Referencia rápida de tipos de estado inicial

Tipo de dato Valor inicial típico Ejemplo de uso
Número 0 Contador, precio
Texto '' Campo de búsqueda
Booleano false Mostrar/ocultar
Arreglo [] Lista de productos
Objeto {} Datos de un formulario

Cuándo usar useState y cuándo no

Usa useState cuando:

  • El componente necesita recordar información entre renders.
  • La información puede cambiar por una acción del usuario.
  • Solo ese componente necesita esa información.

No uses useState cuando:

  • El dato nunca cambia. Usa una constante normal.
  • El dato viene del componente padre. Usa props.
  • El dato lo necesitan muchos componentes distintos. En ese caso se usan soluciones más avanzadas como Context o Redux (temas fuera del alcance de esta lección).

Puntos clave

  • useState devuelve un arreglo de dos elementos: el valor actual y la función para actualizarlo.
  • Nunca modifiques el estado directamente. Siempre usa la función set para que React detecte el cambio y actualice la pantalla.
  • Los inputs controlados usan value y onChange juntos para que React controle el contenido del campo.
  • Cada pieza de información independiente debe tener su propio useState.
  • Cuando el nuevo estado depende del anterior, usa la forma funcional: setValor(prev => prev + 1).

Puntos clave

  • `useState` devuelve un arreglo con dos elementos: el valor actual del estado y la función para actualizarlo. Desestructura siempre como `const [valor, setValor] = useState(inicial)`.
  • Nunca modifiques el estado directamente (por ejemplo, `cantidad = cantidad + 1`). Usa siempre la función `set` para que React detecte el cambio y actualice la pantalla.
  • Los inputs controlados usan `value={estado}` y `onChange={handler}` juntos. Esto le da a React el control total del campo y mantiene la UI sincronizada con el estado.
  • Cuando el nuevo estado depende del valor anterior, usa la forma funcional: `setContador(prev => prev + 1)`. Esto evita errores en actualizaciones rápidas o simultáneas.
  • Llama a `useState` siempre en el nivel superior del componente, nunca dentro de `if`, bucles o funciones anidadas.

Comparte esta lección: