El estado es la memoria de tu componente. Es lo que cambia cuando el usuario interactúa con la app. Cuando cambias el estado, React actualiza automáticamente la pantalla. Sin estado, tu app sería estática y aburrida.
El estado es información que un componente "recuerda". Cuando el estado cambia, el componente se re-renderiza (se dibuja de nuevo).
import { useState } from 'react';
export default function App() {
// useState devuelve un array con 2 elementos:
// 1. El valor actual del estado
// 2. Una función para cambiar el estado
const [contador, setContador] = useState(0);
return (
<div>
<h1>Contador: {contador}</h1>
<button onClick={() => setContador(contador + 1)}>
Aumentar
</button>
</div>
);
}
Cómo funciona useState:
useState(0): Inicializa el estado con valor 0.contador: El valor actual del estado.setContador: La función para cambiar el estado.setContador(5), React actualiza el estado y re-renderiza el componente.El estado puede ser cualquier tipo: números, strings, booleanos, arrays, objetos.
import { useState } from 'react';
export default function App() {
// Estado string
const [nombre, setNombre] = useState("");
// Estado booleano
const [estaVisible, setEstaVisible] = useState(true);
// Estado array
const [tareas, setTareas] = useState(["Tarea 1", "Tarea 2"]);
// Estado objeto
const [usuario, setUsuario] = useState({
nombre: "Juan",
edad: 25,
ciudad: "Madrid"
});
return (
<div>
<p>Nombre: {nombre}</p>
<p>Visible: {estaVisible ? "Sí" : "No"}</p>
<p>Tareas: {tareas.length}</p>
<p>{usuario.nombre} tiene {usuario.edad} años</p>
</div>
);
}
Para tipos simples (números, strings, booleanos), es directo.
import { useState } from 'react';
export default function App() {
const [contador, setContador] = useState(0);
const [nombre, setNombre] = useState("");
const [estaEncendido, setEstaEncendido] = useState(false);
return (
<div>
<!-- Actualizar número -->
<button onClick={() => setContador(contador + 1)}>
Aumentar
</button>
<!-- Actualizar string -->
<input
value={nombre}
onChange={(e) => setNombre(e.target.value)}
placeholder="Escribe tu nombre"
/>
<!-- Actualizar booleano -->
<button onClick={() => setEstaEncendido(!estaEncendido)}>
{estaEncendido ? "Apagar" : "Encender"}
</button>
</div>
);
}
Para arrays, debes crear uno nuevo (no modificar el original).
import { useState } from 'react';
export default function App() {
const [tareas, setTareas] = useState(["Tarea 1", "Tarea 2"]);
// Agregar elemento
const agregarTarea = () => {
setTareas([...tareas, "Nueva tarea"]);
// [...tareas] copia el array y le agrega el nuevo elemento
};
// Eliminar elemento
const eliminarTarea = (index) => {
setTareas(tareas.filter((_, i) => i !== index));
// filter crea un nuevo array sin el elemento en esa posición
};
// Modificar elemento
const modificarTarea = (index, nuevoTexto) => {
const nuevoArray = [...tareas];
nuevoArray[index] = nuevoTexto;
setTareas(nuevoArray);
};
return (
<div>
<button onClick={agregarTarea}>Agregar</button>
<ul>
{tareas.map((tarea, index) => (
<li key={index}>
{tarea}
<button onClick={() => eliminarTarea(index)}>
Eliminar
</button>
</li>
))}
</ul>
</div>
);
}
Para objetos, también debes crear uno nuevo con los cambios.
import { useState } from 'react';
export default function App() {
const [usuario, setUsuario] = useState({
nombre: "Juan",
edad: 25,
ciudad: "Madrid"
});
// Actualizar una propiedad
const actualizarNombre = (nuevoNombre) => {
setUsuario({
...usuario, // Copiar todas las propiedades
nombre: nuevoNombre // Sobrescribir la que cambió
});
};
// Actualizar múltiples propiedades
const actualizarUsuario = () => {
setUsuario({
...usuario,
edad: 26,
ciudad: "Barcelona"
});
};
return (
<div>
<p>{usuario.nombre}, {usuario.edad} años, {usuario.ciudad}</p>
<button onClick={() => actualizarNombre("Ana")}>
Cambiar nombre
</button>
<button onClick={actualizarUsuario}>
Actualizar
</button>
</div>
);
}
A veces necesitas compartir estado entre componentes. La solución es "elevar" el estado al padre.
// Componente hijo
function Boton({ contador, setContador }) {
return (
<button onClick={() => setContador(contador + 1)}>
Aumentar
</button>
);
}
// Componente hijo
function Pantalla({ contador }) {
return <h1>{contador}</h1>;
}
// Componente padre (donde vive el estado)
export default function App() {
const [contador, setContador] = useState(0);
return (
<div>
<Pantalla contador={contador} />
<Boton contador={contador} setContador={setContador} />
</div>
);
}
Crea un carrito que agregue y elimine productos.
import { useState } from 'react';
export default function Carrito() {
const [carrito, setCarrito] = useState([]);
const [producto, setProducto] = useState("");
const [precio, setPrecio] = useState("");
const agregarProducto = () => {
if (producto && precio) {
setCarrito([...carrito, {
id: Date.now(),
nombre: producto,
precio: parseFloat(precio)
}]);
setProducto("");
setPrecio("");
}
};
const eliminarProducto = (id) => {
setCarrito(carrito.filter((item) => item.id !== id));
};
const total = carrito.reduce((sum, item) => sum + item.precio, 0);
return (
<div>
<h1>Carrito de Compras</h1>
<div>
<input
value={producto}
onChange={(e) => setProducto(e.target.value)}
placeholder="Producto"
/>
<input
type="number"
value={precio}
onChange={(e) => setPrecio(e.target.value)}
placeholder="Precio"
/>
<button onClick={agregarProducto}>
Agregar
</button>
</div>
<ul>
{carrito.map((item) => (
<li key={item.id}>
{item.nombre} - ${item.precio}
<button onClick={() => eliminarProducto(item.id)}>
Eliminar
</button>
</li>
))}
</ul>
<h2>Total: ${total.toFixed(2)}</h2>
</div>
);
}
Crea un formulario que valide y guarde datos.
import { useState } from 'react';
export default function Formulario() {
const [datos, setDatos] = useState({
nombre: "",
email: "",
contraseña: ""
});
const [enviado, setEnviado] = useState(false);
const handleChange = (e) => {
const { name, value } = e.target;
setDatos({
...datos,
[name]: value
});
};
const handleSubmit = (e) => {
e.preventDefault();
console.log("Datos enviados:", datos);
setEnviado(true);
setDatos({ nombre: "", email: "", contraseña: "" });
};
return (
<div>
{enviado && <p>✓ Formulario enviado correctamente</p>}
<form onSubmit={handleSubmit}>
<input
type="text"
name="nombre"
value={datos.nombre}
onChange={handleChange}
placeholder="Nombre"
required
/>
<input
type="email"
name="email"
value={datos.email}
onChange={handleChange}
placeholder="Email"
required
/>
<input
type="password"
name="contraseña"
value={datos.contraseña}
onChange={handleChange}
placeholder="Contraseña"
required
/>
<button type="submit">
Enviar
</button>
</form>
</div>
);
}
Usa CodeSandbox (React).