Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

148
Vistas
Componente de reacción obteniendo dimensiones de referencia incorrectas en useEffect

Estoy atascado con este problema con respecto a React.

Estoy construyendo un componente de acordeón, con colapso animado (a través de una transición de altura máxima). Necesito que el acordeón se renderice en estado abierto dependiendo de la propiedad "showOpen".

Inicialmente, si showOpen prop es verdadero, la altura máxima del contenido plegable se establece en 'no establecido', por lo que el contenido es visible. Hasta aquí todo bien.

Después de eso, necesito obtener las dimensiones reales del contenido y establecer un valor de altura máxima específico, ya que las transiciones no funcionarán con 'no establecido'. Estoy usando un gancho useLayoutEffect, que se ejecuta directamente después del montaje del componente. (Estoy usando useLayoutEffect, ya que debería esperar todos los cambios de dom (representación de niños), sin embargo, parece funcionar de la misma manera que con useEffect.

Dentro de useLayoutEffect, no puedo obtener las dimensiones reales del contenido sin el "tiempo de espera sucio". Supongo que el motor de renderizado necesita más tiempo para calcular las dimensiones del contenido, pero pensé que useLayoutEffect debería ejecutarse una vez que esto haya terminado.

Hasta ahora, probé diferentes enfoques usando ResizeObserver, onLoad event y usando ref callback, pero nada de esto funcionó. ResizeObserver y el evento onLoad ni siquiera fueron llamados, por lo que parece que las mutaciones DOM realmente se ejecutaron antes del gancho, pero de alguna manera todavía faltaban las dimensiones correctas en ese momento.

Las soluciones de tiempo de espera funcionan, pero me parecen inaceptables, ya que dependen de algún número de tiempo de espera mágico.

¿Hay algo que me he perdido? ¿Podría sugerir una mejor solución?

SInceramente Gracias.

 const Accordion = ({ label, showOpen, children }) => { const [isOpen, setOpenState] = useState(showOpen); const [height, setHeight] = useState(showOpen ? 'unset' : '0px'); const [chevronRotation, setChevronRotation] = useState<'down' | 'right'>(showOpen ? 'down' : 'right'); const content = useRef<HTMLDivElement>(null); useLayoutEffect(() => { console.log('first effect', content?.current?.getBoundingClientRect().height); // returns 0 setTimeout(() => { console.log( 'timeout effect', content?.current?.getBoundingClientRect().height // returns correct height ); }, 50); }, []); const toggleAccordion = (): void => { if (isOpen) { setOpenState(false); setHeight('0px'); setChevronRotation('right'); } else { setOpenState(true); setHeight(`${filtersContent.current?.scrollHeight}px`); setChevronRotation('down'); } }; return ( <> <div className={classNames(styles.accordionSection)} onClick={toggleAccordion}> <div role="headline">{label}</div> <Chevron width={8} fill={'#6f6f6f'} direction={chevronRotation} /> </div> <div ref={content} style={{ maxHeight: `${height}` }}> {children} </div> </> );

};

about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

Creo que lo que es importante recordar aquí es cómo funciona realmente la pila/cola de llamadas bajo el capó.

setTimeout() se colocará en la cola de trabajos . Piense en la cola de trabajo como una fila/cola para un paseo en un parque de diversiones.

Comienzas desde atrás y esperas tu turno.

Async/await, por ejemplo, utiliza la cola de mensajes .

Puede pensar en la cola de mensajes como el pase rápido del parque de diversiones; te permite ir de la salida de un viaje al FRENTE del siguiente viaje, el mismo viaje del que acabamos de ver setTimeout() ir a la parte de atrás.

Entonces, ¿qué está pasando con este código y cómo se aplican las cosas de la cola?

El comportamiento del gancho de efecto de diseño mezclado con la cola de trabajos es bastante interesante. En resumen, significa que el efecto de diseño no se resolverá/finalizará hasta que se haya hecho TODO lo demás, ya que la devolución de llamada de tiempo de espera será lo último que se ejecutará.

Eso sí, useLayoutEffect está completamente bloqueado hasta después de todas las manipulaciones de DOM, y también se activa de forma sincrónica.

Ver:

  • Bucle de eventos del nodo (ayuda a comprender mejor la idea de las colas)
  • Trabajo ES6 frente a colas de mensajes

Alternativamente, si no está agarrando la referencia correctamente, lo cual es extraño, parece que la mejor solución sería usar un useEffect simple, o incluso mejor, en mi opinión, usar useCallback con useState para lograr lo seguro.

Por ejemplo,

 const [refState, setRefState] = useState<React.MutableRefObject<HTMLDivElement | null>>(null) const cbRef = useCallback((node) => setRefState(node), node) ... return ( <> ... <div ref={cbRef} style={{ maxHeight: `${height}` }}> {children} </div> </> );

La referencia ahora se activará SOLAMENTE después de que el elemento haya terminado de montarse con éxito, y la referencia vivirá en el refState (asumiendo que tenemos un [refState, setRefState] = useState() , como se usa en el ejemplo).

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda