๋ฌดํ ์คํฌ๋กค์ ํ์ฉํ ๊ณ ์์ด ์ฌ์ง์ฒฉ์ ๊ฐ๋จํ๊ฒ ๋ง๋ค์ด๋ณด๋ ๊ฐ์๋ฅผ ๋ค์์๋ค.
๋ฌดํ ์คํฌ๋กค์ ์ธ์คํ์ ๊ฐ์ SNS๋ ์ผํ๋ชฐ์์๋ ๊ฑฐ์ ํ์์ ์ผ๋ก ์ฌ์ฉ๋๋ ๊ธฐ๋ฅ์ด๋ค.
๋ฌดํ ์คํฌ๋กค์ ๊ตฌํํ๋ ๋ฐฉ์์ ํฌ๊ฒ ๋ ๊ฐ์ง ๋ฐฉ์์ด ์๋๋ฐ ์ด๋ฅผ ์ ๋ฆฌํด๋ณด๋ ค๊ณ ํ๋ค.
์ถ์ฒ: https://dmswl98-dev.tistory.com/17
ํ๋์ฉ ์๋ฏธํ๋ ๋ฐ๋ฅผ ์์๋ดค๋ค.
์ถ์ฒ: https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight
์ถ์ฒ: https://developer.mozilla.org/ko/docs/Web/API/HTMLElement/offsetHeight
์ด ์ธ ๊ฐ์ง๋ฅผ ์ด์ฉํ๋ฉด ๋ฌดํ ์คํฌ๋กค์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ ๊ฐ๋ฅํ๋ค.
// scroll ์ด๋ฒคํธ
window.addEventListener('scroll', () => {
// isLoading: ๋ก๋ฉ ์ค ์ฌ๋ถ, totalCount: ์๋ฒ ๋ด ๋ฐ์ดํฐ ๊ฐฏ์, photos: ๋ ๋๋ง๋ ๋ฐ์ดํฐ ๊ฐฏ์
const { isLoading, totalCount, photos } = this.state;
// ๋งจ ์๋๊น์ง ์คํฌ๋กคํ๋์ง ์ฌ๋ถ๋ฅผ ์ฒดํฌ
const isScrollEnded =
window.innerHeight + window.scrollY + 100 >= document.body.offsetHeight;
// ๋งจ ์๋๊น์ง ์คํฌ๋กคํ๊ณ ์๋ฒ์ ํต์ (๋ก๋ฉ) ์ค์ด ์๋๋ฉฐ
// ์๋ฒ ๋ฐ์ดํฐ๊ฐ ๋ชจ๋ ๋ ๋๋ง ๋ ๊ฒ์ด ์๋๋ผ๋ฉด ์ถ๊ฐ๋ก ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์จ๋ค.
if (isScrollEnded && !isLoading && photos.length < totalCount)
onScrollEnded(); // ์์ ์ปดํฌ๋ํธ ๋ฐ์ดํฐ ํธ์ถ
});
๊ธฐ๋ณธ์ ์ธ ๋ก์ง์ ๋ด๊ฐ ๋ณด๊ณ ์๋ ํ๋ฉด ๋์ด(innerHight
)์ ์คํฌ๋กคํ ๋์ด(scrollY
)์ ํฉ์ด ๋ฌธ์ ์ ์ฒด ๋์ด(offsetHeight
)์ ๋์ด์๋ ์์ ์ ์๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๊ฒ ํ๋ ๊ฒ์ด๋ค.
window.innerHeight
+window.scrollY
>=document.body.offsetHeight
;
ํ์ง๋ง ๋ฑ ๋ง๊ฒ ์ค์ ํ๋ฉด ๋ฌด์กฐ๊ฑด ์ตํ๋จ์ ๋ฟ์์ผ๋ง ํ๋ ๋ถํธํจ์ด ์๊ณ margin๊ณผ ๊ฐ์ ์ฌ๋ฐฑ์ผ๋ก ์ธํด ์ธ์์ด ์๋๋ ์ด์๊ฐ ๋ฐ์ํ ์ ์๋ค.
๋ฐ๋ผ์ 100px ์ ๋์ ์ฌ์ ๋ฅผ ๋ฌ์ ์ตํ๋จ๊น์ง ๋ด๋ ค๊ฐ๊ธฐ ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๊ฒ ํ๋ค.
๋ํ ์ตํ๋จ์ ๋ฟ์๋ค๊ณ ๋ฌด์กฐ๊ฑด ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๊ฒ ํ๋ฉด ์๋ฒ ํธ์ถ์ ๋ฌด๋ถ๋ณํ๊ฒ ํ๊ฒ ๋ ์๋ ์๋ค.
๊ทธ๋์ isLoading
์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ ์ค์ผ ๋๋ ์ค๋ณต api ํธ์ถ์ ๋ง์์ฃผ๊ณ
์๋ฒ ๋ด ๋ฐ์ดํฐ ๊ฐฏ์(photos.length < totalCount
)๋ฅผ ์ฒดํฌํด์ ์ ์ฒด ๋ฐ์ดํฐ๊ฐ ๋ชจ๋ ๋ ๋๋ง๋ ํ์๋ ์ถ๊ฐ์ ์ผ๋ก api ํธ์ถ์ด ๋ญ๋น๋์ง ์๋๋ก ํธ๋ค๋ง ์กฐ๊ฑด์ ์ถ๊ฐํด์คฌ๋ค.
IntersectionObserver ๊ฐ์ฒด๋ ๊ฐ์(observe)ํ ๋์์ ์ ํด์ ํด๋น ์์๊ฐ ์ค์ ํ ๋ทฐํฌํธ ๋ด ๊ฒฝ๊ณ์ ๊ต์ฐจํ๋ ์์ ์ ํฌ์ฐฉํ ์ ์๋ค.
IntersectionObserver๋ 1๋ฒ์งธ๋ก ์ฝ๋ฐฑ ํจ์, 2๋ฒ์งธ๋ก observer ์ค์ ์ ๋ํ ์ธ์๋ฅผ ์ ์ํ ์ ์๋ค.
observer์ ๋ํ ์ค์ ์์ฑ์ ์ธ ๊ฐ์ง์ด๋ค.
root
observer์ ๊ฐ์ ๋์์ด ๋ธ๋ผ์ฐ์ ํ๋ฉด์ ๋ค์ด์ค๋ ์์ญ(Box)์ ์๋ฏธํ๋ค.
์ค์ ์ ๋ฐ๋ก ํ์ง ์์ผ๋ฉด ์ต์์ ๋ฌธ์์ ๋ทฐํฌํธ๋ฅผ ์ฌ์ฉํ๋ค. (์ฌ๊ธฐ์๋ body)
rootMargin
root ์์ญ์ margin์ ์ค์ ํ ์ ์๋ค. ๊ธฐ๋ณธ margin ์ค์ ์ฒ๋ผ ์์ฐํ์ข ์์ผ๋ก ์ค์ ๊ฐ๋ฅํ๋ค. ๊ธฐ๋ณธ๊ฐ์ 0px 0px 0px 0px
์ด๋ค.
threshold
๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ์์ฑ์ด์ง ์์๊น ์ถ๋ค. ๊ฐ์ ๋์์ ์ผ๋ง๋ ๋
ธ์ถ๋์์ ๋ ์ฝ๋ฐฑ ํจ์๋ฅผ ์คํํ ์ง๋ฅผ ์ค์ ํ๋ค. 0 ~ 1๊น์ง์ ๊ฐ์ ์ค์ ํ ์ ์๋ค. ๊ธฐ๋ณธ๊ฐ์ 0์ด๋ค.
์๋ฅผ ๋ค์ด 0.5๋ฅผ ์ค์ ํ๋ฉด ๋ฐ ์ ๋ ๋ณด์์ ๋ ๊ฐ์ ๋์์ด ์ ๋ฐ ์ ๋ ๋
ธ์ถ๋์ ๋ ์ฝ๋ฐฑ ํจ์๋ฅผ ์คํํ๋ค.
IntersectionObserver์์์ ๋ฉ์๋๋ ๋ณดํต ๋ ๊ฐ์ง๋ง ์ฌ์ฉํ๋ ๊ฒ ๊ฐ๋ค.
observe
์ unobserve
์ธ๋ฐ ๊ฐ๊ฐ ๊ฐ์๋ฅผ ์ค์ ๋ฐ ํด์ ๊ฐ๋ฅํ๋ค.
const obsever = new IntersectionObserver(
(entries) => {
// entries๋ li ํ๊ทธ๋ก ์ด๋ฏธ์ง ๋ฐ์ดํฐ๊ฐ ๋ค์ด์จ๋ค.
entries.forEach((entry) => {
// isIntersecting์ ๊ฐ์์์๊ฐ root ๋ฐ์ค๋ฅผ ๊ต์ฐจํ๋์ง ์ฌ๋ถ์ด๋ค.
// ๋ง์ฐฌ๊ฐ์ง๋ก isLoading ์ํ์์๋ ์ค๋ณตํด์ ํธ์ถํ์ง ์๋๋ค.
if (entry.isIntersecting && !this.state.isLoading) {
console.log('ํ๋ฉด ๋', entry); // ํ๋ฉด ๋์ธ์ง ํ์ธ
// ๋ฐ์ดํฐ๊ฐ ๋จ์๋ค๋ฉด
if (this.state.totalCount > this.state.photos.length) {
onScrollEnded(); // ์ถ๊ฐ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
} // ๋ค ๊ฐ์ ธ์๋ค๋ฉด
else if (this.state.totalCount === this.state.photos.length) {
// ์ต์ ๋ฒ ํด์
obsever.unobserve(entry.target);
}
}
});
},
{
// ๋ง์ง๋ง ์์๊ฐ ์ ๋ฐ ์ ๋ ๋ณด์ผ ๋ ์ฝ๋ฐฑ ์คํ
threshold: 0.5,
}
);
let $lastLi = null;
// ...
// ๋ค์ ๊ฐ์ ๋์์ ๋ง์ง๋ง ๋ฆฌ์คํธ๋ก ์ค์
const $nextLi = $photos.querySelector('li:last-child');
if ($nextLi !== null) {
// ๋ง์ง๋ง ๋ฆฌ์คํธ๊ฐ ์๋ค๋ฉด ๊ฐ์ ๋
if ($lastLi !== null) {
obsever.unobserve($lastLi);
}
// ๊ฐ์ ๋์ ๊ต์ฒด
$lastLi = $nextLi;
obsever.observe($lastLi);
}
์์์ ๊ตฌํํ IntersectionObserver ๋ก์ง์ ๋ค์๊ณผ ๊ฐ๋ค.
obsever.observe($lastLi)
: ๊ธฐ๋ณธ์ ์ผ๋ก observer์ ๊ฐ์๋์($lastLi
)์ ์ด๋ฏธ ๋ ๋๋ง ๋์ด ์๋ ๋ง์ง๋ง ๋ฆฌ์คํธ ์์($photos.querySelector('li:last-child')
)๋ก ์ ํ๋ค.observer ์์์๋ ๊ฐ์์์์ ์ ๋ฐ(threshold: 0.5,
)์ด ๋ทฐํฌํธ์ ์ตํ๋จ(root๋ฅผ ์ค์ ํ์ง ์์์ผ๋ฏ๋ก)๊ณผ ๊ฒน์น๋์ง ๊ฐ์ํ๋ค.
onScrollEnded()
: ๊ฒน์ณค์ ๊ฒฝ์ฐ ๋ฐ์ดํฐ๊ฐ ๋จ์์๋ค๋ฉด ์ถ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ณ ์ฌ๋ ๋๋งํ๋ค.
$lastLi = $nextLi
, obsever.observe($lastLi)
: ๋ ๋๋ง๋ ๋ง์ง๋ง ์์๋ฅผ ์๋ก์ด ๊ฐ์๋์์ผ๋ก ์ ํ๋ค.
obsever.unobserve($lastLi)
: ์ด๋ฅผ ๋ฐ๋ณตํ๋ค๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ค ๊ฐ์ ธ์๊ฑฐ๋ ๋ง์ง๋ง ๋ฆฌ์คํธ๊ฐ ์์ผ๋ฉด ๊ฐ์๋ฅผ ๋๋ธ๋ค.
๊ฐ์ฌ๋๋ rootMargin์ ๊ฑด๋๋ ค๋ณด๋ ค๊ณ ํ์๋ค๊ฐ ์๊ฐ๋ณด๋ค ๊ธฐ์กด์ Margin๊ณผ๋ ์กฐ๊ธ ๋ค๋ฅด๊ฒ ์๋ํ๋ ๊ฒ ๊ฐ๋ค๊ณ ์กฐ์์ ๋ฏธ๋ฃจ์ จ๋ค. ๋๋ ์ด์ ๋ํด ์ข ๋ ์กฐ์ฌ๋ฅผ ํด๋ณผ ์์ ์ด๋ค.
๐ ํด๋น ๋ด์ฉ์ ๊ณต๋ถํ๋ฉด์ ์ ๋ฆฌํ ๊ธ์ ๋๋ค. ํ๋ฆฐ ๋ถ๋ถ์ด๋ ์คํดํ๊ณ ์๋ ๋ถ๋ถ์ด ์๋ค๋ฉด ํผ๋๋ฐฑ ๋ถํ๋๋ฆฝ๋๋ค.
๊ฒ์์ฒ๊ตญ ํํ๋ฉด์ ๋ฌดํ์คํฌ๋กค ํ ์ ๋๋ฉด ์ฐ๋ฆฌ ๊ฒ์ ๋๊ฐ์ฉ ๋๋ง๋ค์ด์ค๋ฉด๋๋์?๐ซก๐ซก