Detectar elemento con Intersection Observer en React

No creo sea difícil de entender el título del artículo, pero es la forma de como he estado buscando en google y de cómo detectar cierto elemento o sección de una página hecha con React. En busca de hacer un código sencillo y fácil de entender y sin dar muchas vueltas usar Intersection Observer en React puede ser bastante útil para algunos casos, en la mayoría

Que es Intersection Observer?

Nos permite «observar» elementos de forma asincrona cambios de entre elementos o tambien por el viewport, permitiéndonos saber si estamos pasando de una sección o div con un ID que hayamos declarado en nuestro HTML.

Con esto podríamos cambiar de color en el menu de navegacion por ejemplo. Pero también nos puede ayudar con:

Para qué usar Intersection Observer?

Al tener nuestros proyectos creados por componentes y la facilidad de reutilizarlos y al poder crear nuestros propios custom Hooks, Intersection Observer en React es una buena idea.

Los elementos observados nos podrían permitir:

  • Carga en diferido de imágenes o el autoplay de un video u otro contenido a medida que la página se desplaza.
  • Implementación del desplazamiento infinito en sitios web, donde más y más contenido se carga y muestra a medida que se desplaza la página, de forma que el usuario no tiene que pasar páginas.
  • Informes de visualizaciones de anuncios para calcular ingresos por publicidad.

Detectar elementos con Intersection Observer en React

Detectar elementos con Intersection Observer en React

Para mi caso usé Intersection Observer para cambiar de color el menú dependiendo de la sección en la que se encontraba. Ya sea con un click directo o mientras se hacía scroll.

Detectando la sección.

En este caso solo vamos a usar el hook «useRef» que nos «guardará» por así decirlo.

import { useRef } from 'react'

export const Conctact = () => {
    const contactRef = useRef(null)

    return (
        <div ref={contactRef} className="contact" id='contact'>
            <h1>Contact</h1>
        </div>
    )
}

Ahora que tenemos «guardada» toda nuestra sección de contacto. Podremos acceder al «anchor» del div y usaremos para detectar cuando el scroll pase por «encima»

Guando la información observada.

Creo que iré paso por paso…

Primero vamos a necesitar dos elementos donde podamos almacenar los datos que vamos a recibir.

    const [contact, setContact] = useState(null)
    const [entryObserver, setEntryObserver] = useState(false)

En «contact» vamos a guardar nuestro elemento detectado. Y solo cambiará cuando «entryObserver» sea true.

Y para ello vamos a usar de una vez la API Intersection Observer en React. En este caso con useEffect

      useEffect(() => {
        const observer = new IntersectionObserver(
          entries => {
            const entry = entries[0]
            setEntryObserver(entry.isIntersecting)
            if (entryObserver) {
                setContact('#contact')
            }
          },
          {
            rootMargin: '0px 0px 0px',
            root: null,
            threshold: 0.5
          }
        )
        observer.observe(contactRef.current)
      }, [entryObserver])

Lo primero que hicimos fue declarar una nueva constante que es igual a la API de IntersectionObserver. Pero además le vamos declarando que elemento va a estar observando en el parametro «observe«. Para ello pasamos nuestro «contactRef» que ya habíamos declarado antes.

const observer = new IntersectionObserver()
observer.observe(contactRef.current)

Dentro de Intersection, tenemos una función que nos devolverá varios elementos. Pero el que nos interesa en este caso es «entries«.

Entre sus elementos usaremos «entry.isIntersecting» nuestro estado a true.

          entries => {
            const entry = entries[0]
            setEntryObserver(entry.isIntersecting)
            if (entryObserver) {
                setContact('#contact')
            }
          },

Con esto ya hemos detectado en qué parte de la página está e usuario. Pero si queremos «personalizar» aún más la detección. Podemos jugar con los valores de las opciones de la API de

Como resultado, tendríamos el siguiente código.

import React, { useState, useRef, useEffect } from 'react'

export const Conctact = () => {
    const contactRef = useRef(null)
    const [contact, setContact] = useState(null)
    const [entryObserver, setEntryObserver] = useState(false)

    useEffect(() => {
        const observer = new IntersectionObserver(
          entries => {
            const entry = entries[0]
            setEntryObserver(entry.isIntersecting)
            if (entryObserver) {
                setContact('#contact')
            }
          },
          {
            rootMargin: '0px 0px 0px',
            root: null,
            threshold: 0.5
          }
        )
        observer.observe(contactRef.current)
      }, [entryObserver])
    return (
        <div ref={contactRef} className="contact" id='contact'>
            <h1>Contact</h1>
        </div>
    )
}

Al usar useEffects, vamos a detectar cada vez que haya un cambio en entryObserver para volver a ejecutarlo y cambiar los estados que necesitemos cambiar.

Conclusiones

Si queremos que toda nuestra página este siendo observada, deberíamos colocar dicho codigo en cada sección. Pero al ser un codigo que se puede reutilizar, lo ideal seria crear un Custom Hoook y enviar los datos de cada sección.

Ahora, si están empeñados a no usar librerías y partirse la cabeza como yo. Les recomendaria que le den un vistazo react-scroll que hace todo esto lo que vimos, de una manera mucho más sencilla.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *