Elevar el estado significa sacar el estado de los componentes que necesitan compartirlo y llevarlo a su padre común más cercano. El padre guarda el valor, lo pasa hacia abajo como prop y pasa una función que los hijos llaman para cambiarlo, así que cada hijo renderiza a partir de una sola copia del estado.
Haz clic en "Show" en cualquier panel: se abre y el que estaba abierto se cierra. Solo un panel puede estar abierto a la vez porque los paneles no lo deciden por sí mismos. App guarda openIndex, y cada Panel solo recibe isOpen y una función onOpen.
El problema: un estado que debe coincidir
Empieza por la versión obvia, donde cada panel es dueño de su propio estado isOpen. Cada panel funciona, pero los paneles no saben nada unos de otros, así que nada impide que dos estén abiertos a la vez.
Abre ambos paneles: se quedan abiertos juntos. El estado en React es privado del componente que lo declara, así que un hermano no puede leerlo ni reiniciarlo. Cuando dos componentes tienen que coincidir, el estado tiene que vivir por encima de ambos.
Elevar el estado en tres pasos
Convertir el segundo ejemplo en el primero lleva tres cambios.
- Quita el estado del hijo. Borra
useStateenPanely leeisOpendesde las props. El hijo ya no decide si está abierto. - Pasa el valor y una forma de cambiarlo desde el padre.
PanelrecibeisOpeny un callbackonOpen. El hijo llama aonOpen()cuando se hace clic en su botón; no sabe qué hace el padre con eso. - Agrega el estado al padre común.
AppdeclaraopenIndexy lo convierte en props para cada panel:isOpen={openIndex === 1}yonOpen={() => setOpenIndex(1)}.
El padre común más cercano es el componente más bajo que renderiza todos los componentes que necesitan el estado. Aquí es App. Si los paneles estuvieran dentro de un componente Faq, el estado iría en Faq, no más arriba.
Después de elevarlo, Panel está controlado por su padre en el mismo sentido que un input controlado: muestra lo que dicen las props y comunica los cambios mediante un callback. La página sobre componentes controlados vs no controlados cubre la misma idea para elementos de formulario.
Una única fuente de verdad
Cuando dos partes de la pantalla muestran el mismo dato, guarda ese dato una vez y calcula todo lo demás a partir de él. Un conversor de temperatura es el caso clásico: los inputs de Celsius y Fahrenheit siempre deben coincidir, así que no pueden guardar cada uno su propio número.
Escribe en cualquiera de los dos campos y el otro lo sigue. El estado es un solo dato: el número que el usuario escribió por última vez y en qué escala estaba. El otro campo se calcula a partir de él durante el renderizado, así que el campo en el que escribes siempre conserva exactamente lo que escribiste. Cambia el estado inicial a { value: '212', scale: 'f' } y el mensaje bajo los inputs cambia a "Water boils."
Guardar un número en Celsius y otro en Fahrenheit en dos piezas de estado significaría que cada manejador tiene que actualizar ambos, y la primera vez que a uno se le olvide, los dos inputs no coincidirán. Un solo valor guardado no puede contradecirse.
Pasar el setter hacia abajo
Un hijo solo puede cambiar el estado del padre mediante una función que el padre le da. Puedes pasar el propio setter (onSelect={setColor}) o una función que hace más (onOpen={() => setOpenIndex(1)}). Darle a la prop un nombre de estilo evento como onSelect u onChange, en lugar de setSelected, hace que el hijo no sepa cómo guarda el valor el padre, así el padre puede cambiar eso más adelante sin tocar al hijo.
ColorPicker y Preview nunca hablan entre sí. El selector comunica una elección hacia arriba, App la guarda y el nuevo valor fluye hacia abajo a ambos.
Cuándo no elevar el estado
Elevar tiene un costo. Cuando el estado vive en un padre, cada cambio renderiza el padre y, por defecto, todos sus hijos, incluidos los que no usan el estado. Eleva solo hasta el padre común más cercano, y deja dentro de un componente el estado que solo ese componente usa.
Escribe en la caja y mira la consola: solo SearchBox se renderiza en cada pulsación. Ahora mueve query a App y pásalo a SearchBox como props. Cada pulsación registra entonces también ProductList, aunque la lista no usa la búsqueda. Si la lista sí filtrara por la búsqueda, elevar sería la decisión correcta, porque ambos componentes dependerían del mismo valor.
La pregunta que hay que hacerse es "¿quién necesita leer este valor?". Si la respuesta es un componente, el estado se queda ahí. Si son varios, va a su padre común más cercano.
Cuando elevar va demasiado lejos
A veces el padre común más cercano está muy arriba en el árbol, y el valor tiene que pasar por varios componentes que solo lo reenvían. Eso es el prop drilling. Unas pocas capas de props están bien y son fáciles de seguir. Cuando el mismo valor viaja por muchas capas, o casi todos los componentes lo necesitan (el usuario con sesión iniciada, el tema, el idioma), léelo con useContext en lugar de pasarlo a mano. El contexto cambia cómo llega el valor a los hijos; el estado en sí sigue viviendo en un padre, así que sigue estando elevado.
Preguntas frecuentes
¿Qué significa elevar el estado en React?
Mover una pieza de estado desde los componentes que la usan hasta su padre común más cercano. El padre es dueño del estado y pasa el valor, junto con una función para cambiarlo, a los hijos como props.
¿Cómo comparten estado dos componentes hermanos en React?
Los hermanos no pueden leer el estado del otro. Pon el estado en su padre compartido, pasa el valor a ambos y pasa un setter (o un manejador como onChange) al que lo cambia. Así ambos hermanos renderizan a partir del mismo valor.
¿Cómo actualiza un componente hijo el estado del padre?
El padre pasa una función como prop, por ejemplo onSelect={setSelected} u onSelect={(id) => setSelected(id)}, y el hijo la llama. El estado se queda en el padre; el hijo solo pide el cambio.
¿Cuándo no debo elevar el estado?
Cuando solo un componente usa el estado. Elevarlo más de lo necesario hace que el padre renderice en cada cambio y reparte props por componentes a los que no les importan. Mantén el estado lo más cerca posible de donde se usa.
¿Cuál es la alternativa a elevar demasiado el estado?
Si te encuentras pasando las mismas props por muchas capas, lee el valor compartido con contexto (useContext), o reorganiza para que los componentes que lo necesitan queden más cerca entre sí.