Hookpedia
Ctrl + K
Repositório no GitHub

useOnScreen

Compartilhar no Twitter

08 de novembro de 2018

Gist
Sandbox

Esse hook te permite facilmente detectar quando um elemento é visível na tela e também especificar o quanto do elemento deve estar visível antes de ser considerado dentro da tela. Perfeito para Lazy loading de imagens ou ativar animações quando o usuário desce para uma determinada seção.

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

// Uso
function App() {
  // Referência para o elemento que nós queremos detectar se está em tela
  const ref = useRef();
  // Chamamos o hook passando a referência e o margin de root
  // Neste caso, ele seria considerado em tela se mais ...
  // ... que 300px do elemento estiver visível.
  const onScreen = useOnScreen(ref, "-300px");

  return (
    <div>
      <div style={{ height: "100vh" }}>
        <h1>Descer para a próxima sessão...</h1>
      </div>
      <div
        ref={ref}
        style={{
          height: "100vh",
          backgroundColor: onScreen ? "#23cebd" : "#efefef",
        }}
      >
        {onScreen ? (
          <div>
            <h1>Hey Eu estou na tela</h1>
            <img src="https://i.giphy.com/media/ASd0Ukj0y3qMM/giphy.gif" />
          </div>
        ) : (
          <h1>Descer mais 300px do topo dessa sessão</h1>
        )}
      </div>
    </div>
  );
}

// Hook
function useOnScreen(ref, rootMargin = "0px") {
  // Estado e setter para armazenar se o elemento está visível
  const [isIntersecting, setIntersecting] = useState(false);

  useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => {
        // Atualizar o estado quando o callback do observador dispara
        setIntersecting(entry.isIntersecting);
      },
      {
        rootMargin,
      }
    );
    if (ref.current) {
      observer.observe(ref.current);
    }
    return () => {
      observer.unobserve(ref.current);
    };
  }, []); // Array vazio que garante que o efeito é executado apenas na montagem e desmontagem

  return isIntersecting;
}

Criado por @guilherssousa, mantido por 1 pessoas 💗