头图

Original link: https://bobbyhadz.com/blog/react-check-if-element-in-viewport

Author: Borislav Hadzhiev

The text starts here~

Overview

In React, check if an element is within viewport bounds:

  1. Set the ref attribute on the element.
  2. Use the IntersectionObserver API to track whether an element intersects the viewport.
 import {useEffect, useRef, useState, useMemo} from 'react';

export default function App() {
  const ref1 = useRef(null);
  const ref2 = useRef(null);

  const isInViewport1 = useIsInViewport(ref1);
  console.log('isInViewport1: ', isInViewport1);

  const isInViewport2 = useIsInViewport(ref2);
  console.log('isInViewport2: ', isInViewport2);

  return (
    <div>
      <div ref={ref1}>Top div {isInViewport1 && '| in viewport ✅'}</div>

      <div style={{height: '155rem'}} />

      <div ref={ref2}>Bottom div {isInViewport2 && '| in viewport ✅'}</div>
    </div>
  );
}

function useIsInViewport(ref) {
  const [isIntersecting, setIsIntersecting] = useState(false);

  const observer = useMemo(
    () =>
      new IntersectionObserver(([entry]) =>
        setIsIntersecting(entry.isIntersecting),
      ),
    [],
  );

  useEffect(() => {
    observer.observe(ref.current);

    return () => {
      observer.disconnect();
    };
  }, [ref, observer]);

  return isIntersecting;
}

This example shows us how to check if an element is within the viewport. IntersectionObserver API enables us to check if a given element intersects the document.

useIsInViewport hook receives a ref object pointing to the element we want to track.

IntersectionObserver

IntersectionObserver The constructor receives a function, which is called with an array of entry . entry is an array that contains all the target elements of obeserver . The visibility of these elements is already above or below one of the ratios intersection observer .

Each entry describes how much a given element intersects the root element (document). We deconstructed this entry because our IntersectionObserver can only track one element (the one we set ref ).

We call the observe() method, passing it the element we want to track observer.observe(ref.current) .

Whenever an element enters or exists in the viewport, the function we pass to the IntersectionObserver() constructor is called, which then updates the state variable.

 // 👇️ gets called every time element enters or leaves viewport
new IntersectionObserver(([entry]) =>
  setIsIntersecting(entry.isIntersecting),
)

If we set the ref object's element in the viewport, the useIsInViewport hook will return true . If the element is not in the viewport, the hook will return false .

Note that on initial render, the useIsInViewport hook will return false . Because we passed the initial value for useState false . const [isIntersecting, setIsIntersecting] = useState(false);

If you want to track changes in the return value of a hook, use the useEffect hook and add the value to the hook's dependencies.

 const isInViewport1 = useIsInViewport(ref1);
console.log('isInViewport1: ', isInViewport1);

useEffect(() => {
  // 👇️ listen for changes
  console.log(isInViewport1);
}, [isInViewport1]);

chuck
303 声望41 粉丝