El hook useState
Introducción
useState es un hook en React que permite agregar y manejar el estado en componentes funcionales. Antes de React Hooks, solo los componentes de clase podían manejar el estado, pero ahora es posible hacerlo de manera sencilla en componentes funcionales.
1. Qué es el Estado en React? #
El estado es una forma de almacenar datos que cambian con el tiempo y que afectan la forma en que un componente se renderiza. Por ejemplo, el estado puede ser un contador, un valor de un formulario, o incluso un estado de "cargando".
2. Cómo usar useState? #
Ejemplo básico: Contador #
1import React, { useState } from "react"; 2 3function Contador() { 4 // Declaramos el estado con useState 5 const [contador, setContador] = useState(0); 6 7 return ( 8 <div> 9 <p>Has hecho clic {contador} veces</p> 10 <button onClick={() => setContador(contador + 1)}>Incrementar</button> 11 </div> 12 ); 13} 14 15export default Contador;
Explicación #
useState(0)inicializa el estado con un valor de0.[contador, setContador]devuelve un array con:contador: El valor actual del estado.setContador: Una función para actualizar el estado.
- Cuando hacemos clic en el botón, llamamos a
setContadorpara incrementar el valor.
3. Actualización del Estado #
Ejemplo: Cambiar texto dinámicamente #
1import React, { useState } from "react"; 2 3function CambiarTexto() { 4 const [texto, setTexto] = useState("¡Hola, mundo!"); 5 6 return ( 7 <div> 8 <p>{texto}</p> 9 <button onClick={() => setTexto("¡Has cambiado el texto!")}> 10 Cambiar texto 11 </button> 12 </div> 13 ); 14} 15 16export default CambiarTexto;
Explicación #
Cada vez que haces clic en el botón, setTexto actualiza el estado y React vuelve a renderizar el componente con el nuevo valor de texto.
4. Múltiples Estados #
Puedes tener varios estados en un solo componente.
1import React, { useState } from "react"; 2 3function Perfil() { 4 const [nombre, setNombre] = useState("Carlos"); 5 const [edad, setEdad] = useState(25); 6 7 return ( 8 <div> 9 <p>Nombre: {nombre}</p> 10 <p>Edad: {edad}</p> 11 <button onClick={() => setNombre("Ana")}>Cambiar Nombre</button> 12 <button onClick={() => setEdad(edad + 1)}>Incrementar Edad</button> 13 </div> 14 ); 15} 16 17export default Perfil;
Explicación #
Puedes manejar estados independientes para nombre y edad. Cada useState gestiona un estado diferente.
5. Estado Inicial con Valores Complejos #
El estado inicial puede ser un objeto o array.
Ejemplo: Estado como Objeto #
1function Perfil() { 2 const [perfil, setPerfil] = useState({ nombre: "Carlos", edad: 25 }); 3 4 const cambiarNombre = () => { 5 setPerfil({ ...perfil, nombre: "Ana" }); 6 }; 7 8 const incrementarEdad = () => { 9 setPerfil({ ...perfil, edad: perfil.edad + 1 }); 10 }; 11 12 return ( 13 <div> 14 <p>Nombre: {perfil.nombre}</p> 15 <p>Edad: {perfil.edad}</p> 16 <button onClick={cambiarNombre}>Cambiar Nombre</button> 17 <button onClick={incrementarEdad}>Incrementar Edad</button> 18 </div> 19 ); 20} 21 22export default Perfil;
Explicación #
- El estado inicial es un objeto:
{ nombre: "Carlos", edad: 25 }. - Usamos el operador spread (
...) para copiar el objeto anterior al actualizar una propiedad, evitando sobrescribir las demás.
6. useState con Arrays #
Ejemplo: Lista de Tareas #
1function ListaTareas() { 2 const [tareas, setTareas] = useState([]); 3 4 const agregarTarea = () => { 5 setTareas([...tareas, `Tarea ${tareas.length + 1}`]); 6 }; 7 8 return ( 9 <div> 10 <ul> 11 {tareas.map((tarea, index) => ( 12 <li key={index}>{tarea}</li> 13 ))} 14 </ul> 15 <button onClick={agregarTarea}>Agregar Tarea</button> 16 </div> 17 ); 18} 19 20export default ListaTareas;
Explicación #
- El estado
tareases un array inicializado como vacío. setTareasactualiza el array, agregando una nueva tarea usando spread (...).
7. Consideraciones Importantes #
-
useState es Asíncrono:
React no garantiza que el estado se actualice inmediatamente después de llamar asetState.1const incrementar = () => { 2 setContador(contador + 1); 3 setContador(contador + 1); // Esto NO incrementa dos veces 4};Solución: Usa una función para actualizar el estado basado en el valor anterior:
1setContador((prev) => prev + 1); 2setContador((prev) => prev + 1); // Ahora sí incrementa dos veces -
No Modifiques el Estado Directamente:
Siempre usa la funciónsetState. Modificarlo directamente no funciona:1// ¡NO! 2contador = contador + 1; -
Re-renderización:
Cambiar el estado hace que el componente se vuelva a renderizar automáticamente.
Resumen del tema
Conceptos clave #
- Sintaxis de
useState:const [estado, setEstado] = useState(valorInicial). - Inmutabilidad de Objetos y Arrays: nunca mutar el estado directamente (
estado.push()); crear siempre nuevas referencias con el operador spread (setEstado([...estado, nuevo])). - Actualizaciones Funcionales (
prev => ...): requeridas cuando el nuevo valor depende del estado previo para evitar condiciones de carrera por loteado (batching). - Inicialización Perezosa (Lazy Initializer): pasar una función
useState(() => calculoCostoso())para ejecutar lógica pesada solo en el renderizado inicial.
Qué debes recordar #
Usa useState para estado local reactivo, respetando siempre la inmutabilidad y utilizando actualizadores funcionales setEstado(prev => ...) ante valores dependientes.