¿Cuál es la diferencia entre state y props en React?
Ver respuesta — intenta responderla en voz alta primero
Las props son datos que un componente recibe de su padre y no puede modificar. El estado (state) es un dato que el propio componente posee y puede cambiar con el tiempo; cuando cambia, React re-renderiza el componente. La pregunta clave es: ¿quién es el dueño del dato?
Las dos cosas son "datos que usa un componente", pero se diferencian en la propiedad y el control:
- Props: vienen de afuera. El componente las recibe, las lee y las usa, pero no las modifica. Si el padre pasa un valor nuevo, el hijo se re-renderiza con ese valor.
- State: vive adentro. El componente lo crea con
useState, es su dueño y lo actualiza con la funciónset. Cada actualización dispara un re-render de ese componente (y de sus hijos).
Reglas prácticas para decidir:
- ¿El dato cambia con el tiempo por interacción del usuario (un input, un contador)? → estado.
- ¿El dato viene de otro componente o es configuración fija? → props.
- ¿Se puede calcular a partir de props o de otro estado? → ni uno ni otro: calcúlalo en el render.
- ¿Dos hermanos necesitan el mismo dato? → el estado sube al padre común ("levantar el estado") y baja a ambos como props. Un mismo dato puede ser estado en el padre y prop en el hijo.
import { useState } from "react";
// Hijo: recibe todo por props, no tiene estado propio.
type MarcadorProps = { puntos: number; onSumar: () => void };
function Marcador({ puntos, onSumar }: MarcadorProps) {
// `puntos` es una prop: aquí solo se lee.
return (
<div>
<p>Puntos: {puntos}</p>
<button onClick={onSumar}>Sumar</button>
</div>
);
}
// Padre: es el dueño del dato, así que lo guarda como estado.
function Juego() {
const [puntos, setPuntos] = useState(0); // estado inicial: 0
// "puntos" es ESTADO aquí y viaja como PROP al Marcador.
return <Marcador puntos={puntos} onSumar={() => setPuntos((p) => p + 1)} />;
}
// Comportamiento esperado: render inicial "Puntos: 0". Al hacer clic,
// el padre actualiza su estado y el hijo recibe la prop nueva: "Puntos: 1".
Copiar una prop a un estado local "para poder usarla":
type Props = { nombre: string };
function Perfil({ nombre }: Props) {
// MAL: si el padre cambia `nombre`, este estado se queda con el valor viejo,
// porque useState solo usa el valor inicial en el PRIMER render.
const [nombreLocal] = useState(nombre);
return <p>{nombreLocal}</p>;
}
function PerfilBien({ nombre }: Props) {
return <p>{nombre}</p>; // BIEN: siempre refleja la prop actual
}
La corrección: si el dato viene del padre, úsalo directo desde las props. Solo copia una prop a estado si de verdad quieres un valor inicial que luego vivirá por su cuenta (por ejemplo, un borrador editable).
"La diferencia está en quién es el dueño del dato. Las props vienen del padre y son de solo lectura: el hijo las consume pero no las modifica. El estado es un dato interno del componente, creado con
useState, y cuando lo actualizo con su funciónset, React re-renderiza el componente para reflejar el cambio. Uso estado para datos que cambian por interacción del usuario, y props para configurar componentes desde afuera. Y si dos hermanos necesitan el mismo dato, levanto el estado al padre común y lo bajo como props."
Tienes un componente Termostato que muestra una temperatura y dos botones (+ y -), y un padre Casa que también debe mostrar la temperatura actual en un título. ¿Dónde debe vivir el estado? Impleméntalo.
Ver solución
import { useState } from "react";
// El estado vive en Casa (el padre común), porque dos partes lo necesitan.
type TermostatoProps = { temperatura: number; onCambiar: (delta: number) => void };
function Termostato({ temperatura, onCambiar }: TermostatoProps) {
return (
<div>
<button onClick={() => onCambiar(-1)}>-</button>
<span> {temperatura} grados </span>
<button onClick={() => onCambiar(1)}>+</button>
</div>
);
}
function Casa() {
const [temperatura, setTemperatura] = useState(21);
return (
<main>
<h1>Temperatura actual: {temperatura} grados</h1>
<Termostato temperatura={temperatura} onCambiar={(d) => setTemperatura((p) => p + d)} />
</main>
);
}