๐ค ๋ฌดํ ์คํฌ๋กค์ด๋?
์ปจํ ์ธ ๋ฅผ ํ์ด์งํ๋ ๊ธฐ๋ฒ ์ค ํ๋๋ก ์คํฌ๋กค์ ์ด์ฉํด
๋งจ ์๋๊น์ง ๋๋ฌํ ๋ ์๋ก์ด ์ปจํ ์ธ ๋ฅผ ๋ถ๋ฌ์ค๋ ๋ฐฉ์์ ๋งํ๋ค.
๐ช ๊ตฌํ ๋ฐฉ์
์คํฌ๋กค์ ๋๊น์ง ๋ด๋ ธ์ ๋ fetch๋ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ์๋ฆฌ๋จผํธ์ ๊ณ์ ์ถ๊ฐ(appendChild)ํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํ๋ค.
๊ตฌํ ๋ฐฉ์์ ํฌ๊ฒ ๋ ๊ฐ์ง์ด๋ค.
1. scroll ์ด๋ฒคํธ๋ฅผ ์ด์ฉํ ๋ฐฉ๋ฒ
- ์ ํต์ ์ธ ๋ฐฉ์
- window์ scroll ์ด๋ฒคํธ๊ฐ ์ผ์ด๋ ๋๋ง๋ค ๋ธ๋ผ์ฐ์ ํ๋ฉด์ ๋์ด, ์คํฌ๋กค๋ฐ์ ์์น๋ฅผ ์ด์ฉํด body(์ปจํ ์ธ )์ ๋๊น์ง ๋ค๋ค๋์ผ๋ฉด ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐฉ์์ ๋งํ๋ค.
- window.innerHeight : ํด๋ผ์ด์ธํธ์์ ๋ณด์ฌ์ง๋ ํ๋ฉด ์ค ํญ, url ์ฃผ์์ฐฝ, ๋ถ๋งํฌ ํญ์ ์ ์ธํ ๋ธ๋ผ์ฐ์ ์ ๋์ด
- window.scrollY : ํ์ฌ ์คํฌ๋กค๋ฐ ์์น
- document.body.offsetHeight : body์ height
- window.innerHeight + window.scrollY : (ํญ, url ์ฃผ์์ฐฝ, ๋ถ๋งํฌ ํญ์ ์ ์ธํ)๋ธ๋ผ์ฐ์ ์ ๋์ด + ์ฌ์ฉ์์ ์คํฌ๋กค Y ๊ฐ
- window.innerHeight + window.scrollY ๊ฐ์ด ํ์ฌ body์ ๋์ด ๊ฐ๋ณด๋ค ๊ฐ๊ฑฐ๋ ํฐ ๊ฒฝ์ฐ ์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด๋ค.
window.addEventListener("scroll", () => {
// 100์ ๋ํ๋ฉด ์คํฌ๋กค์ ๋๊น์ง ๋ด๋ฆฌ๊ธฐ 100px ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ฌ ์ ์๋ค.
const isScrollEnded =
window.innerHeight + window.scrollY + 100 >= document.body.offsetHeight;
// totalCount : api์ ๋ฐ์ดํฐ์ ์ ์ฒด ๊ธธ์ด
// photos.length: ํ์ฌ ๋๋๋ง๋ ๋ฐ์ดํฐ์ ๊ธธ์ด
const { photos, totalCount, isLoading } = this.state;
if (isScrollEnded && !isLoading && photos.length < totalCount) {
onScrollEnded();
}
});
๐ฃ isLoading์ ์ํ ์กด์ฌ ์ด์
๋ฐ์ดํฐ๋ฅผ ์ด๋ฏธ ์์ฒญํ์์๋ ๊ณ์ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
์ด ๊ฒฝ์ฐ isLoading ์ํ๋ฅผ ๋์ด ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๊ณ ์๋ต๋ฐ๊ธฐ ์ ๊น์ง๋ ์ฌ์์ฒญ์ ํ์ง ์๋๋ก ํ ์ ์๋ค.
๐ฃ totalCount์ ์กด์ฌ ์ด์
์ด๋ฏธ api์ ๋ง์ง๋ง ๋ฐ์ดํฐ๊น์ง ๋ชจ๋ ๊ฐ์ ธ์์์๋ ๋ถ๊ตฌํ๊ณ 1) ์คํฌ๋กค์ ๋งจ ์๋ ๋ด๋ฆฐ ์ํ, 2) isLoading์ด false์ธ ๊ฒฝ์ฐ, ์ด ๋ ๊ฐ์ง๊ฐ ์ฐธ์ผ ๋ ๊ณ์ ์์ฒญ์ ๋ณด๋ด๋ ์ํฉ์ด ๋ฐ์ํ๋ค.
์ด ๊ฒฝ์ฐ api์ ๋ฐ์ดํฐ ์ ์ฒด ๊ฐ์(totalCount)์ ํ์ฌ๊น์ง ๋๋๋ง๋ ๋ฆฌ์คํธ์ ๊ฐ์(photos.length)๋ฅผ ๋น๊ตํด ํด๊ฒฐํ ์ ์๋ค.
2. Intersection Observer๋ฅผ ์ด์ฉํ ๋ฐฉ๋ฒ
- ์ต๊ทผ์ ์ฌ์ฉํ๋ ๋ฐฉ์
- observe, unobserve๋ฅผ ์ฌ์ฉํด ๊ตฌํํ๋ค.
- threshold ๊ฐ์ผ๋ก observe ๋์์ด ์ผ๋ง๋ ๋ ธ์ถ๋์๋์ง์ ๋ฐ๋ผ ๋์ํ๊ฒ ํ ์ ์๋ค.
Intersection Observer ์ค์
์ฒซ ๋ฒ์งธ ์ธ์๋ก ์ฝ๋ฐฑ ํจ์, ๋ ๋ฒ์งธ ์ธ์๋ก observer์ ์ค์ ์ฌํญ์ ์ ์ํ ์ ์๋ค.
- root: ๊ด์ฐฐ ๋์์ด ๋ธ๋ผ์ฐ์ ํ๋ฉด์ ๋ค์ด์์์ ๊ฐ์งํ๋ ์์ญ์ด๋ค.
- rootMargin: ๊ด์ฐฐ ๋์์ ๊ฐ์งํ๋ ์์ญ์ margin์ ์ด์ฉํด ๋ฒ์๋ฅผ ํ์ฅํ ์ ์๋ค. ๊ธฐ๋ณธ๊ฐ์ '0px 0px 0px 0px'์ด๋ฉฐ, ๋ฐ๋์ ๋ฌธ์์ด๋ก ๋จ์์ ํจ๊ป ์์ฑํด์ผ ํ๋ค.
- threshold: ๊ด์ฐฐ ๋์์ด ๋ธ๋ผ์ฐ์ ํ๋ฉด ๋ด์ ์ผ๋ง๋ ๋ณด์์ ๋ ์ฝ๋ฐฑ ํจ์๋ฅผ ํธ์ถํ ์ง ๊ฒฐ์ ํ๋ ๊ฐ์ ๋งํ๋ค.
// ์ฒซ๋ฒ์งธ ์ธ์๋ ์ฝ๋ฐฑํจ์, ๋ ๋ฒ์งธ ์ธ์๋ ์ค์
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
const { photos, totalCount, isLoading } = this.state;
// ๋ก๋ฉ ์ค์๋ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค์ง ์๋๋ก ํด์ผ ํจ
if (entry.isIntersecting && !isLoading) {
if (photos.length < totalCount) {
onScrollEnded();
}
}
});
},
{
// 1์ธ ๊ฒฝ์ฐ ์คํฌ๋กค์ ์ด์ฉํด ๊ด์ฐฐ ๋์์ด ๋ชจ๋ ๋ณด์ธ ๊ฒฝ์ฐ์ ์ฝ๋ฐฑ ํจ์๊ฐ ์คํ๋๋ค.
threshold: 1,
}
);
// ์ค๋ต
this.render = () => {
// ์ค๋ต
let $lastLi = null;
// ๋ค์ ๊ด์ฐฐ ๋์์ ๋ง์ง๋ง์ ๋ฆฌ์คํธ ์์๋ก ํ๋ค.
const $nextLi = $photos.querySelector("li:last-child");
if ($nextLi !== null) {
if ($lastLi !== null) {
// ๋ง์ง๋ง ์์๊ฐ null์ธ ๊ฒฝ์ฐ์๋ ๊ด์ฐฐํ์ง ์๋๋ค.
observer.unobserve($lastLi);
}
$lastLi = $nextLi;
observer.observe($lastLi); // ๊ด์ฐฐ ๋์ ๋ฑ๋ก
}
};
'Javascript' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
SessionStorage๋ฅผ ์ด์ฉํด ์บ์ ๊ตฌํํ๊ธฐ (0) | 2022.11.23 |
---|---|
[JS] DocumentFragment, Template tag (0) | 2022.10.26 |
[JS] ํด๋ก์ (Closures) ์ดํดํ๊ธฐ (0) | 2022.10.18 |
spread์ rest ๋น๊ตํ๊ธฐ (0) | 2022.07.28 |
ํ๋กํ ํ์ (Prototype) ์ดํดํ๊ธฐ 2 (0) | 2022.07.17 |