TIL no.64 - IntersectionObserver

김종진·2021년 8월 4일
0

React

목록 보기
16/17
post-thumbnail

IntersectionObserver API

특정 요소(타겟 요소)가 타겟 요소의 부모나 viewport에 교차하는지를 비동기적으로 감지해서 교차할때마다 콜백함수를 호출하는 API

이를 이용하여 스크롤 동작에 관련된 기능을 구현할 수 있다.

  1. 비동기 무한 스크롤 UI
  2. 스크롤 위치에 따른 애니메이션 UI

객체 생성과 callback, root, rootMargin, threshold

const io = new IntersectionObserver(callback, {
  root: null, // 또는 scrollable 한 element
  rootMargin: '0px', // 아무것도 안쓰면 0px,
  threshold: 0.5 // 0.0 부터 1.0 사이의 숫자를 지정할 수 있습니다. 배열 값도 가능
})

1. root

root 의 값은 Element 또는 null
target (관측 대상)을 감싸는 element를 지정하는 것인데
만약 null 로 지정한다면 viewport가 된다.

2. rootMargin

root 요소를 감싸는 margin 값을 지정한다.
문자열로 작성해야 하며, css의 margin 처럼 px 또는 % 단위로 작성할 수 있다.
threshold나 교차 상태를 점검할 때 margin 값이 지정 되어 있다면, 이를 활용하여 계산이 된다.

3. threshold

target element가 root 와 몇 % 교차했을 때, callback을 실행할지 결정하는 값이다.

threshold: 0.5 라면 스크롤 하는 중에 element 가 50% 보였을 때 실행할 callback을 실행한다.

4. callback

요소가 관측됐을 때 실행시킬 함수

무한 스크롤 구현

무한 스크롤 구현에는 여러 가지 방법이 있는데 IntersectionObserver를 이용하면 코드나 성능상으로도 효율성있게 구현할 수 있다.

(...)
  const getCardtData = async (perPage) => {
    try {
      setIsLoading(true);
      await axios
        .get(`${SERVER}api/users?per_page=${perPage}&page=1`)
        .then(function (res) {
          setCardDataAPI(res.data);
          setIsLoading(false);
          setError(false);
        });
    } catch (error) {
      setError(true);
    }
  };

  useEffect(() => {
    perPage !== 0 && getCardtData(perPage);
  }, [perPage, error]);

  const onIntersect = useCallback(
    (entries) => {
      if (userInput) return;
      const target = entries[0];
      if (target.isIntersecting) setPerpage((perPage) => perPage + 3);
    },
    [userInput]
  );

  useEffect(() => {
    if (!loader.current) return;

    const io = new IntersectionObserver(onIntersect, { threshold: 1 });
    io.observe(loader.current);

    return () => io && io.disconnect();
  }, [loader, userInput]);
  
  (...)
  
  <div ref={loader} className="loader">
    {isLoading && <Spinner />}
  </div>

나는 로딩 스피너를 보여주는 엘리먼트가 관측되면 카드를 추가로 받아서 보여주는 무한 스크롤을 구현했다.

스크롤 애니메이션 구현

스크롤을 내려가면서 엘리먼트가 관측됬을 때 애니메이션이 발생하도록 할 수 있다.

  const options = {
    root: null,
    rootMargin: "0px 0px 30px 0px",
    threshold: 0,
  };

  useEffect(() => {
    const io = new IntersectionObserver((entries, observe) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          entry.target.classList.add("active");
          observe.unobserve(entry.target);
        }
      });
    }, options);

    const boxes = document.querySelectorAll(".box");
    boxes.forEach((el) => {
      io.observe(el);
    });
  }, []);
  

box class의 엘리먼트가 관측됬을때 아래에서 올라오는 애니메이션을 구현 했다.

https://animista.net/play/basic/slide[링크텍스트]

이번에 알게된 사이트인데 다양한 애니메이션 효과와 그 코드를 볼 수 있는 너무너무나 유용한 사이트이다.

profile
FE Developer

0개의 댓글