jueves, 12 de marzo de 2026

Ciclo de renderizado en React y efectos

 ¿En qué fases del ciclo de render de React puede incidir mi código?

En React tu código puede incidir en distintas fases del ciclo de render, y entenderlas te ayuda a decidir dónde colocar lógica:

  • Render phase: React ejecuta tu componente como función y construye el árbol de elementos virtuales. Aquí no deberías realizar efectos secundarios (fetch, manipulación del DOM), solo calcular qué se renderiza en base al estado y las props.

  • Commit phase: React aplica los cambios al DOM real. En esta fase se ejecutan los effects (useEffect, useLayoutEffect). Aquí sí podés interactuar con APIs externas, suscribirte a eventos, modificar el DOM o disparar animaciones.

  • Passive effects: Los useEffect se ejecutan después de que el navegador pinta la pantalla, ideales para lógica asincrónica (fetch, timers, listeners).

  • Layout effects: Los useLayoutEffect se ejecutan justo después de que React aplica cambios al DOM pero antes de que el navegador pinte, lo que permite medir el DOM o aplicar ajustes inmediatos.

👉 En resumen:

  • Durante el render: solo lógica pura (sin efectos).

  • Durante el commit: efectos secundarios (useEffect, useLayoutEffect).

  • Entre renders: tu código incide al actualizar estado o props, lo que dispara un nuevo ciclo.

¿Querés que te arme un diagrama visual del ciclo de render de React mostrando dónde encajan render, commit, useEffect y useLayoutEffect?

Sí.

Aquí tenés el diagrama visual del ciclo de render de React que pediste, mostrando claramente las fases de Render, Commit y Actualización, junto con dónde encajan useEffect y useLayoutEffect.

https://copilot.microsoft.com/th/id/BCO.1401c45c-f675-41c1-bf13-396b82c6bba9.png

📌 Cómo leerlo

  • Fase de Render: React ejecuta tu componente y construye el Virtual DOM. Aquí no se permiten efectos secundarios.

  • Fase de Commit: React aplica los cambios al DOM real.

    • useLayoutEffect: se ejecuta inmediatamente después de actualizar el DOM, antes del repintado. Ideal para medir o ajustar el DOM.

    • useEffect: se ejecuta después del repintado, perfecto para lógica asincrónica (fetch, timers, listeners).

  • Actualización: cualquier interacción o cambio de estado/props reinicia el ciclo.

Este esquema te ayuda a visualizar en qué momento tu código puede incidir y qué tipo de lógica corresponde a cada fase.

¿Querés que te arme también un ejemplo práctico con un componente React que muestre cómo se comportan useEffect y useLayoutEffect en la práctica?

¿Es correcta mi hipótesis de que en un efecto se pueden actualizar estado que dependa de otro estado del mismo componente?

Sí, tu hipótesis es correcta: dentro de un efecto (useEffect), podés actualizar un estado que depende de otro estado del mismo componente. De hecho, es una práctica común para encadenar actualizaciones o sincronizar valores derivados.

Eso sí, hay que tener cuidado con dos cosas:

  1. Evitar ciclos infinitos: si el efecto actualiza un estado que vuelve a disparar el mismo efecto, necesitás controlar las dependencias cuidadosamente.

  2. Usar funciones de actualización seguras: cuando el nuevo estado depende del anterior, usá la forma setX(prev => ...) para evitar problemas de asincronía.

📌 Ejemplo práctico

tsx
const [valor, setValor] = useState(0);
const [doble, setDoble] = useState(0);

useEffect(() => {
  setDoble(valor * 2); // actualiza estado derivado
}, [valor]); // solo se ejecuta cuando cambia `valor`

👉 Este patrón es útil para mantener sincronizados estados relacionados sin recalcular en cada render.

¿Querés que te arme un ejemplo más complejo con useEffect que sincronice múltiples estados en un componente de odontograma, como estado de pieza y alerta de patología?

¿En qué orden se suceden un efecto que depende de un estado y el renderizado del componente?

En React, el orden es claro: primero ocurre el render del componente, luego se ejecutan los efectos (useEffect). Esto significa que cuando un estado cambia, React vuelve a renderizar el componente, y después del renderizado, ejecuta los efectos que dependen de ese estado.

📌 Flujo simplificado

  1. Cambio de estado → se dispara un nuevo render.

  2. Render phase → React ejecuta la función del componente.

  3. Commit phase → React actualiza el DOM.

  4. Post-render → se ejecutan los efectos (useEffect) que tienen ese estado en su lista de dependencias.

✅ Implicación práctica

Si en un useEffect dependés de un estado, ese efecto se ejecutará después de que el componente se haya renderizado con el nuevo valor. Esto te permite usar el efecto para sincronizar, calcular derivados, o disparar lógica asincrónica basada en ese nuevo estado.

¿Querés que te arme un ejemplo con useEffect que observe un estado y actualice otro, mostrando cómo se encadenan los renders y efectos?

¿Después de un efecto que actualiza un estado siempre React va a detectar un cambio y re-renderizar el componente?

No siempre. React solo re-renderiza si el estado que actualizás en el efecto cambia de valor o referencia respecto al anterior.

📌 Detalles importantes

  • Caso 1: el estado cambia realmente

    tsx
    useEffect(() => {
      setCount(prev => prev + 1);
    }, [trigger]);
    

    👉 Si trigger cambia y el efecto incrementa count, React detecta un nuevo valor y re-renderiza.

  • Caso 2: el estado se setea con el mismo valor

    tsx
    useEffect(() => {
      setCount(prev => prev); // mismo valor
    }, [trigger]);
    

    👉 React ve que no hay diferencia y no re-renderiza.

  • Caso 3: objetos/arrays React compara referencias, no contenido.

    tsx
    setData(prev => ({ ...prev })); // nueva referencia
    

    👉 Aunque el contenido sea igual, React detecta un objeto nuevo y dispara re-render. Pero si hacés mutación in-place y devolvés el mismo objeto, no habrá re-render.

✅ Regla de oro

  • React re-renderiza solo si el estado cambia (valor primitivo distinto o referencia distinta en objetos/arrays).

  • Si el efecto actualiza el estado con el mismo valor/referencia, no habrá re-render.

¿Querés que te arme un mini experimento en React con logs (console.log) para que veas en qué casos el efecto dispara un re-render y en cuáles no?

Si estado1 y estado2 son dos estados de un componente, y además estado1 es una dependencia de un efecto que modifica estado2 ¿El componente se puede renderizar dos veces, una después de que cambia estado1 y otra vez después de que cambia estado2?

Exacto, tu razonamiento es correcto: en ese escenario el componente puede renderizarse dos veces seguidas.

📌 Flujo detallado

  1. Cambio de estado1

    • React detecta el cambio → dispara un nuevo render.

    • El componente se renderiza con el nuevo valor de estado1.

  2. Ejecución del efecto dependiente de estado1

    • Después del render y commit, se ejecuta el useEffect que depende de estado1.

    • Ese efecto actualiza estado2 mediante setEstado2(...).

  3. Cambio de estado2

    • React detecta que estado2 cambió → dispara otro render.

    • El componente se renderiza nuevamente, ahora con el nuevo valor de estado2.

✅ Resultado

  • Sí, el componente se renderiza dos veces:

    • Una por el cambio de estado1.

    • Otra por el cambio de estado2 provocado por el efecto.

⚠️ Consideraciones

  • Este patrón es válido, pero puede generar renders adicionales que afecten el rendimiento si se repite mucho.

  • Si estado2 es siempre un valor derivado de estado1, puede ser más eficiente calcularlo directamente en el render (ej. const estado2 = estado1 * 2) en lugar de mantenerlo como estado separado.

  • Mantener estados derivados solo tiene sentido si necesitás que estado2 se actualice de forma asincrónica o independiente.

¿Querés que te arme un ejemplo práctico en React con logs para que veas en consola cómo se disparan los dos renders en ese caso?

No hay comentarios: