No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Reto: sigamos extiendo el DOM

12/16
Recursos

Aportes 4

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

Estuvo genial el reto, aprendí mucho de useEffect leyendo la documentación oficial de cómo remover las dependencias de useEffect buscando una solución al bug del segundo reto.
.
En resumen, aprendí que el linter siempre estará pendiente de que agreguemos en el array de dependencias de useEffect todos los valores reactivos que usemos dentro del mismo, como props o estados. Como onLazyLoad es una función dentro de los props del componente LazyImage, React lo trata como un valor reactivo. Sin embargo, no queremos agregar esta función en las dependencias de useEffect, porque lo único que nos interesa de onLazyLoad es obtener sus datos, más no ejecutar el callback de useEffect cada vez que onLazyLoad cambie.
.
La mejor solución en la documentación es utilizar el hook (en fase experimental a la fecha de escribir este comentario 15/03/23) useEffectEvent. Este hook le indica a useEffect que vamos a utilizar un valor reactivo dentro del mismo, pero no queremos que ‘reaccione’ a sus cambios, sino que solamente lo use para lectura. Este hook al estar en fase experimental, preferí no usarlo pero está bastante interesante para cuando salga.
.
Al final, opté por la opción que React no recomienda, que es desactivar el linter. Como en todo, cada cosa a su momento, y en este caso desactivar el linter es la opción que mejor se adapta a mi código porque solamente quiero leer lo que me arroja onLazyLoad, más no reaccionar a sus cambios. Es de esos momentos cuando la solución menos recomendada resulta ser la más óptima para un caso específica, o por lo menos la más sencilla según yo

interface LazyImageProps extends ImgHTMLAttributes<HTMLImageElement> {
  src: string
  alt: string,
	// especificamos que onLazyLoad es un valor opcional de tipo void que aceptará un argumento de tipo HTMLImageElement
  onLazyLoad?: (node: HTMLImageElement) => void
}

export default function LazyImage({src, alt, onLazyLoad, ...imgOptionalAttrs}: LazyImageProps) {
  
  const node = useRef<HTMLImageElement>(null)
  
  const [currentSrc, setCurrentSrc] = useState(defaultImg)
  
  useEffect(() => {
    const intersectionObserver = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          setCurrentSrc(src)
					// ya que onLazyLoad es un valor opcional, validamos que sea verdadero y lo ejecutamos pasando el target de la entrada como argumento el cual contiene todos los datos del elemento img
          onLazyLoad && onLazyLoad(entry.target as HTMLImageElement)
					// le digo al intersectionObserver que deje de observar a img luego de entrar al viewport y ejecutar el código de arriba
          intersectionObserver.unobserve(entry.target)
        }
      })
    })
    
    node.current && intersectionObserver.observe(node.current)
    return () => { intersectionObserver.disconnect() }
	// DANGER ZONE: le digo al linter que ignore la línea de abajo
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [src])

  return (
    <img ref={node} src={currentSrc} alt={alt} {...imgOptionalAttrs} />
  )
}

Yo lo solucione un poco diferente sin pasar el nodo y usando prevState

Mi solucion

interface Props extends ImgHTMLAttributes<HTMLImageElement> {
    src: string,
    onLazyLoad?: (node: HTMLImageElement) => void
}
useEffect(() => {
        const observer = new IntersectionObserver((entries) => {
            entries.forEach((entry) => {
                if(entry.isIntersecting) {
                    console.log("Hey")
                    setCurrentSrc(src)

                    if(node.current) {
                        onLazyLoad && onLazyLoad(node.current)
                        observer.disconnect()
                    }
                }
            })
        })

        if(node.current) {
            observer.observe(node.current)
        }

        return () => {
            observer.disconnect()
        }
}, [src, onLazyLoad])

Bueno no entendí el reto my bien, lo unico que pude enteder es que tipo de dato era la funcion onLazyLoad la cual logré, más allá de eso no entendí mucho los retos. Aquí dejo la primera parte del primer reto, OJO, NO ESTÁ COMPLETO

Código

type LazyImageProps = {
  src: string;
  onLazyLoad?: ()=> void 
};