No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Reg铆strate

Comienza en:

4D
2H
59M
39S

Componentes que extienden elementos DOM

11/16
Recursos

Aportes 3

Preguntas 1

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Yo utilice interface y herede de ImgHTMLAttributes<HTMLImageElement>

interface Props extends ImgHTMLAttributes<HTMLImageElement> {
}

con esto ya funcionar铆a pero tendriamos que validar que src tenga algun valor cada vez que queramos utilizarlo utlizarlo por que en la imagenes src: string | undefined, pero esto lo solucione definiendo src solamente como string

interface Props extends ImgHTMLAttributes<HTMLImageElement> {
    src: string
}

Componentes que extienden elementos DOM

Nuestros componentes evolucionan, por lo que es importante crear componentes escalables que puedan tener funcionalidades m谩s complejas en el futuro鈥 Vamos a ver como podemos hacer que nuestro componente que hemos trabajado sea un componente m谩s global, escalable, y reutilizable.

De RandomFox.tsx a LazyImage.tsx

import { useRef, useEffect, useState } from "react"

type Props = { image: string }

export default function LazyImage( { image }: Props ):JSX.Element {  
  const node = useRef<HTMLImageElement> (null)
  const [src, setSrc] = useState<string>("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIwIiBoZWlnaHQ9IjMyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiLz4=")

  useEffect(() => {
    const observer = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          setSrc(image)
        }
      })
    })

    if (node.current) {
      observer.observe(node.current)
    }
    
    return () => {
      observer.disconnect()
    }

  },[image])

  return (
    <img ref={node} src={src} className="w-80 h-auto rounded-lg bg-gray-300" />
  )
}

Listo, ahora supongamos que una de nuestras compa帽eras desarrolladoras necesita a帽adir el evento onCLick={} en nuestro componente, veamos como hacer esto:
App.tsx

function App():JSX.Element {
  ...

  return (
    <main className="App">
      ...
      {
        foxes.map((fox, index) => (
          <div key={index} className="p-4">
						{/* Esto nos deber铆a dar un error */}
            <LazyImage image={fox} **onClick={() => console.log('Hola')}** />
          </div>
        ))
      }

    </main>
  )
}

LazyImage.tsx

// actualizamos los tipos a帽adiendo el onClick
type Props = { image: string, onClick: () => void }

export default function LazyImage( { image, onClick }: Props ):JSX.Element {  
  ...

  return (
    <img ref={node} src={src} className="w-80 h-auto rounded-lg bg-gray-300" **onClick={onClick}** />
  )
}

Si probamos el componente, veremos que funciona, pero, 驴acaso esto escala? Recordemos que como desarrolladores tenemos que hacer componentes globales, escalables, y reutilizables, por ello, podemos cambiar esto para en caso de que alguna de nuestras compa帽eras quiera a帽adir funcionalidad extra, esta sea sencilla de implementar. Veamos como:

LazyImage.tsx

/* Importamos el tipo de dato que nos aparece cuando hacemos hover cualquiera
de los eventos de image (como aprendimos antes) */
import type { ImgHTMLAttributes } from "react"

// Creamos dos nuevos tipos de datos
type LazyImageProps = { image: string }
type ImageNativeTypes = ImgHTMLAttributes<HTMLImageElement>

// Los sumamos, haciendo que estos sean un solo tipo de dato
type Props = LazyImageProps & ImageNativeTypes

// recibimos todas las propiedades que soportamos de img con el spread operator
export default function LazyImage( { image, ...imgProps}: **Props** ):JSX.Element {  
  return (
		{/* todas las propiedades que recibe un img soportan autom谩tica e impl铆citamente */}
    <img ... {...imgProps} />
  )
}

Ya de esta forma estamos recibiendo todos los par谩metros que puede recibir un <img /> en React (title, onClick, className, etc). Y como queremos que nuestro componente sea reutilizable, los estilos y personalizaci贸n del componente deber铆an ir en el padre. Vamos a hacer m谩s cambios importantes:

LazyImage.tsx

import { useRef, useEffect, useState } from "react"
import type { ImgHTMLAttributes } from "react"

// actualizamos image para que ahora sea src para no causar confusi贸n
**type LazyImageProps = { src: string }**
type ImageNativeTypes = ImgHTMLAttributes<HTMLImageElement>

type Props = LazyImageProps & ImageNativeTypes

export default function LazyImage( { **src**, ...imgProps }: Props ):JSX.Element {  
  const node = useRef<HTMLImageElement> (null)

	// a src lo cambiaremos a currentSrc paraevitar sobreescritura
  const **[currentSrc, setCurrentSrc]** = useState<string>("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIwIiBoZWlnaHQ9IjMyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiLz4=")

	// corregimos los datos a recibir
  useEffect(() => {
    const observer = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          **setCurrentSrc(src)**
        }
      })
    })
  
    if (node.current) {
      observer.observe(node.current)
    }
    
    return () => {
      observer.disconnect()
    }

  },[**src**])

  return (
    **<img ref={node} src={currentSrc} {...imgProps} />**
  )
}

App.tsx

import { useState } from "react"
import LazyImage from "./components/LazyImage"
import type { MouseEvent } from "react"

const random = (num: number):number => {
  return Math.floor(Math.random() * num) + 1
}

function App():JSX.Element {
  const [foxes, setFoxes] = useState<string[]> ([])

  const addNewFox = (event: MouseEvent<HTMLButtonElement>):void => {
    event.preventDefault()

    const newImage: string = `https://randomfox.ca/images/${random(123)}.jpg`
    setFoxes([
      ...foxes,
      newImage
    ])
  }

  return (
    <main className="App">
      <h1 className="text-3xl font-bold text-indigo-600 p-6">Random Fox</h1>
      <button onClick={addNewFox} className="">A帽adir zorro</button>
      {
        foxes.map((fox, index) => (
          <div key={index} className="p-4">
						{/* Utilizamos el atributo src y a帽adimos la personalizaci贸n en el componente padre */}
            <LazyImage **scr={fox}** className="w-80 h-auto rounded-lg bg-gray-300" onClick={() => console.log('Hola')} />
          </div>
        ))
      }

    </main>
  )
}

export default App

Hemos logrado crear un componente global, escalable, y reutilizable. El cual utiliza las convenciones m谩s convenientes para que nuestro equipo de trabajo tenga una buena experiencia de desarrollo al momento de utilizar nuestro c贸digo, haci茅ndolo f谩cil de entender y f谩cil de mantener a lo largo del tiempo.

Excelente Explicacion鈥