
infinite scroll에서 scroll이 특정 포지션을 지나갈 때, 아이템을 추가로 로드하기 위해 필요한 Intersection Observer API.
Intersection Observer: 타겟 엘리먼트와, 타겟 엘리먼트의 부모나 뷰포트가 교차하는 부분의 변화를 비동기적으로 관찰하는 API이다.
공식문서에서 말하는,
Intersection Observer API는
document에서의viewport 사이의 intersection 내의 변화를 Intersection Observer API는
웹이 발전함에 따라 이러한 변화를 체크하는 것의 필요성이 높아졌고 그래서 나오게 된 API.
getBoundingClientRect()로 실제 엘리먼트의 offset등을 측정하는 방식으로 이루어졌는데, view 안에 인터섹션을 확인해줘야 하는 요소가 있다고 생각했을 때, 성능상의 문제를 가져올 수 있다. 😱😱export const useIntersection = () => {
const [isView, setIsView] = useState(false);
const elemRef = useRef<null | Element | undefined>(null);
const setRef = (elem: null | Element | undefined) => {
elemRef.current = elem;
};
useEffect(() => {
if (!elemRef.current) return;
const observer = new IntersectionObserver((entries) => {
entries.forEach(
(entry) => {
if (entry.isIntersecting) {
setIsView(true);
}
},
{
rootMargin: '-50px',
threshold: 0.8,
}
);
});
observer.observe(elemRef.current);
return () => observer.disconnect();
}, []);
return [isView, setRef] as const;
};
const Components = () => {
const [isViewId, setIsViewId] = useState('0');
const elemRef = useRef<null[] | Element[]>([]);
const setRef = (elem: null | Element, i: number) => {
elemRef.current[i] = elem;
};
useEffect(() => {
if (elemRef.current.length === 0) return;
const observer = new IntersectionObserver((entries) => {
entries.forEach(
(entry) => {
if (entry.isIntersecting) {
setIsViewId(entry.target.id);
}
},
{
rootMargin: '0',
threshold: 0.2,
}
);
});
elemRef.current.forEach((element) => {
observer.observe(element as Element);
});
return () => observer.disconnect();
}, []);
return (
<div>
{selections.map((item, i) => {
return (
<div key={item.id} ref={(e) => setRef(e, i)} >
// ... 생략
</div>
)
</div>
)
}
react-cool-inview라이브러리로 좀 더 깔끔하고 쉽게.. 적용해보기!
yarn add react-cool-inview
# or
npm install --save react-cool-inview
import useInView from "react-cool-inview";
const App = () => {
const { observe, unobserve, inView, scrollDirection, entry } = useInView({
threshold: 0.25, // Default is 0
onChange: ({ inView, scrollDirection, entry, observe, unobserve }) => {
// Triggered whenever the target meets a threshold, e.g. [0.25, 0.5, ...]
unobserve(); // To stop observing the current target element
observe(); // To re-start observing the current target element
},
onEnter: ({ scrollDirection, entry, observe, unobserve }) => {
// Triggered when the target enters the viewport
},
onLeave: ({ scrollDirection, entry, observe, unobserve }) => {
// Triggered when the target leaves the viewport
},
// More useful options...
});
return <div ref={observe}>{inView ? "Hello, I am 🤗" : "Bye, I am 😴"}</div>;
};
import useInView from "react-cool-inview";
const App = () => {
const { observe, inView } = useInView({
onEnter: ({ unobserve }) => unobserve(),
});
return (
<div ref={observe}>
{inView ? "Hello, I am 🤗" : "Bye, I am 😴"}
</div>)
;
};