-
[프리온보딩코스 과제 회고 #1] 무한 스크롤(Infinite Scroll)🏄♀️ 원티드X위코드 프리온보딩코스 2021. 7. 27. 20:54
1. 무한 스크롤의 원리
화면을 스크롤할 때 콘텐츠의 끝 부분을 감지하고, 다음 페이지를 불러와 현재 페이지에 이어 붙인다.
2. 구현 방법
- 전통적인 스크롤 감지(onScroll event) : 유저가 scroll을 하면 이벤트가 발생하고 현재 scroll 위치가 페이지에 끝에 닿았는지 판단한다. 하지만 이 경우 scroll 이벤트는 굉장히 빈번하게 발생하기 때문에 성능 최적화에 위배되는 문제가 있다. 그렇기 때문에
throttle
작업이 추가적으로 필요하다. - Intersection Observer API : DOM 엘리먼트 간에 영역이 겹쳐지는 걸 감시한다. Intersection Observer API를 사용하면 scroll, resize와 같은 비싼 비용의 이벤트를 좀 더 쉽고 좋은 퍼포먼스로 사용할 수 있다.
- useRef : list의 마지막 요소에만 선택적으로 ref를 달아주고, ref가 있을 때, 새롭게 데이터를 fetch하는 방법이다.
→ 위와 같이 무한 스크롤을 구현할 수 있는 여러 가지 방법이 있었지만, 우리가 선택한 방법은 Intersection Observer API를 활용하여 구현하는 것! 이 방법을 채택하게 된 이유는 HTML, CSS, Javascript가 개입하지 않아도 되기 때문이다.
3. 작업 내용
3.1 구현 사항
- 마크업, css 스타일링
- Data Fetch API 호출 함수 작성
- Intesection Observer를 활용한 Custom Hook 작성
- Infinite Scroll 기능 구현
- 각 기능별 폴더 및 파일 분리
3.2 폴더 구조
📂 src > api > getCommentData.js : Data Fetch API 호출 함수
📂 src > components > InfiniteScroll.js : Infinite Scroll 기능
📂 src > hooks > useIntersectObserver.js : Intesection Observer를 활용한 Custom Hook
📂 src > constants > index.js : 상수 저장 파일
📂 src > App.js : Infinite Scroll 컨테이너
📂 src > App.css : 전체 스타일 css 파일
📂 src > index.css : global reset css 파일3.3 작업 플로우
작업 플로우는 우선, getCommentData.js 파일에 데이터를 fetch하여 가져오는 API 함수를 먼저 만들고, 그 후에 App.js에 무한 스크롤 기능을 작성하였다. 그러고 나서 분리할 수 있는 코드들을 hooks 폴더, components 폴더와 constants 폴더에 각각 useIntersectObserver.js, InfiniteScroll.js와 index.js로 분리하였다.
3.4 결과 화면
4. 과제 회고
4.1 새롭게 알게 된 것🆕
- url 호출할 때, params 객체를 보내 query string까지 불러올 수 있다!
이전에는 axios.get(`https://jsonplaceholder.typicode.com/comments?_page=${page}&_limit=${LIMIT}`) 이런 방식으로 api를 호출했었는데, params 객체를 넣어주는 식으로 작업하는 게 훨씬 더 나은 거 같다!
📂 src > api > getCommentData.js
📂 src > App.jsconst API_ENDPOINT = `https://jsonplaceholder.typicode.com/comments`; const LIMIT = 10; . . const res = await axios.get(`${API_ENDPOINT}`, { params: { _page: page, _limit: LIMIT, }, });
const [page, setPage] = useState(1); const data = getCommentData(page);
- Intersection Observer API의 options
root
: 타겟의 visibility(가시성)를 검사하기 위해 뷰포트 대신 사용할 요소 객체를 지정한다.null
인 경우 브라우저의 뷰포트가 디폴트로 사용된다.rootMargin
: 바깥 여백(margin)을 이용해 root의 범위를 확장하거나 축소할 수 있다!rootMargin
이 있으면threshold
계산할 때,rootMargin
영역 만큼 더 계산한다. 그렇기 때문에 이를 주면 뚝뚝 끊기는 느낌이 아닌, 좀 더 스무스하게 스크롤하여 로딩하는 느낌을 줄 수 있다.threshold
: observer가 실행되기 위해 visibility가 얼마나 필요한 지 백분율로 표시한다. 설정한 비율이 노출될 때마다 callback 함수를 실행시킨다!
const options = { root: null, rootMargin: "200px", threshold: 0.01, };
4.2 생각해보기!💡
- usecallback을 사용하지 않을 때, 생기는 에러
→ usecallback을 지웠을 때, state가 겹쳐지는 등 데이터가 덮어씌워지는 현상이 발생했는데, 이는 두 번째 인자로 빈 배열을 삽입하지 않아 state가 바뀔 때마다 새로 호출되었기 때문에 생긴 에러이다. 두 번째 인자로 빈 배열을 삽입해야 해당 컴포넌트가 최초로 호출될 때 한 번만 호출된다! - useEffect에 dependency array로 callback을 왜 쓰는지?
→ dependency array를 넘겨주지 않으면 매번 새로고칠 때마다 새로 호출된다. 이는 성능적으로 좋지 않기 때문에 dependency array를 넘겨주어 조건부로, 변동사항이 있는 경우에만 새로 렌더를 할 수 있게끔 하여 성능을 개선시켜줄 수 있다. - 무한 스크롤이 SEO적인 측면에서는 불리하다고 하는데, 무한 스크롤을 고집해야 하는 이유가 있을까?
→ 무한 스크롤 포스팅을 찾아보던 중 어떤 한 블로그에서 "무한 스크롤이 SEO적인 측면에서는 불리하다고 해서 페이지네이션을 더 선호한다"라는 댓글을 보고 의문이 들었다! SEO적인 측면에서 불리하다면 쓰는 이유가 무엇일까에 대해서 생각을 해보았고, 아무래도 UX적인 측면을 고려해서라고 결론을 내렸다.
SEO를 조금 포기하더라도 뭔가 딱 무한 스크롤로 유저에게 더 많은 데이터를 스무스하게 보여줄 수 있는 것에 초점을 둔다면 무한 스크롤을 쓰는 거 아닐까!라는 생각을 하였는데, 성상님도 역시나 똑같은 생각을 하고 계셨다!
무한 스크롤과 페이지네이션 모두 저마다의 장단점을 가지고 있기 때문에 트렌드에 맞춰 선택하기보다는 각자의 서비스 플랫폼의 방향에 맞춰서 뭐가 더 잘 어울릴까를 따져보는 게 관건인 거 같다!
🔗 더 알아보기 페이지네이션 VS 무한 스크롤 : 자사에 적합한 UX 고르는 법 - ( [ {isIntersecting} ] ) 이건 대체 무슨 문법인가..? 🤔
→ 성상님이 공유해주신 유튜브 강의 중 ( [ {isIntersecting} ] ) 이런 문법이 등장을 하였고... 한눈에 봐서는 이해가 가지 않았다.
친절한 성상님이 >>>거의 멘토님 수준으로<<< 이 문법을 설명해주셨는데 다 듣고 나서 정말 무릎을 탁 쳤다.💡const fetchMoreObserver = new IntersectionObserver(([{ isIntersecting }]) => { // do something });
우리 코드로 미루어보면, new IntersectionObserver(handleObserver, options);에서 handleObserver는 화살표함수로, new IntersectionObserver( (entries) => {}, options);로 사용할 수 있는데! 여기서 entries는 배열이기 때문에 배열 비구조화 할당 + 객체 비구조화 할당을 사용한 것!
여기서 배열 비구조화 할당이란, 아래 코드와 같이
const array = [1] const [one] = array; // 즉, one === 1
표현이 되는 것이고, 객체 비구조화 할당은 property 이름을 자동으로 할당해주는 역할을 하는데, 이때entries
는 원소가 하나인 배열이므로const [a] = entries
하면a
가entries
의[0]
번째 원소로 할당되고,a
안에 있는isInterSecting
을{ interSecting }
으로 함으로써 바로 매개변수로 사용할 수 있는 것이다!
진짜 완전 이해가 잘 가게 설명해준 성상님께 다시 한번 cheers 🥂!!
4.3 이번 과제를 통해 느낀 점
페어 프로그래밍은 아예 처음이라 좀 긴장을 많이 했었는데 되게 재밌었다! 아무래도 똑같은 코드를 두 명이서 같이 보면서 고민하고 짜다 보니 혼자서 짜는 것보다 훨씬 더 수월하고 빠르게 코드를 짤 수 있었다. (에러가 발생해도 두 명이서 고민하니까 해결 시간이 두 배로 단축!!👍) 그리고 운이 좋게 MBTI 궁합이 정말 잘 맞는 짝꿍(@농담곰 성상님)을 만나서 더더욱 유쾌하고 명쾌하게 작업을 진행할 수 있었다! 같은 문제를 가지고도 다양하게 해석하고, 그 생각을 공유하는 과정이 너무 즐거웠고!(이렇게 좋은데 그동안 어떻게 혼자 공부했나 싶다😅) 궁금했던 점들을 같이 해결하다 보니 확실히 혼자서 하던 때보다는 더욱 효율적이었던 거 같다! (이쯤 되면 모든 팀플 과제에 mbti 궁합 별 팀 빌딩의 도입이 시급하다😆ㅎㅎ) 인생 첫 짝코딩이었는데 첫 단추를 잘 꿴 것 같아 아주 뿌듯하다!
예상 시간보다 훨씬 빨리 기능 구현을 다 해서 조금 여유롭게 리팩토링과 README 편집 및 과제 회고 블로그까지 작성할 수 있었다. +) favicon까지 설정하고...ㅎㅎ🏄
▼ 이번 과제의 한 줄 요약: 모르는 것과 고민거리는 나누면 나눌수록 좋다...👍
5. 도움을 주신 분들 🙇♀️
- https://swimfm.tistory.com/entry/무한-스크롤-Infinite-Scroll-페이징-구현해보기-예제
- https://ghur2002.medium.com/react에서-infinite-scroll-구현하기-128d64ea24b5
- https://y0c.github.io/2019/06/30/react-infinite-scroll/
- https://velog.io/@suyeonme/react-Infinite-Scroll-구현하기
- https://velog.io/@doondoony/IntersectionObserver
- https://heropy.blog/2019/10/27/intersection-observer/
- https://pks2974.medium.com/intersection-observer-간단-정리하기-fc24789799a3
'🏄♀️ 원티드X위코드 프리온보딩코스' 카테고리의 다른 글
[프리온보딩코스 과제 회고 #3] 권한 관리와 대시보드 그리고 유효성 검사 (0) 2021.08.08 [프리온보딩코스 주간 회고 #1] 치료가 필요할 정도로 심각한 '블로그 중독증'입니다. (4) 2021.08.02 [프리온보딩코스 세션 회고 #2] React Foundation과 첫 번째 과제 리뷰 (5) 2021.08.02 [프리온보딩코스 과제 회고 #2] 상품 조회 이력과 필터링 그리고 랜덤 로딩하기 (7) 2021.08.01 [프리온보딩코스 세션 회고 #1] 취업 성패를 결정하는 Business Manner (2) 2021.07.28 - 전통적인 스크롤 감지(onScroll event) : 유저가 scroll을 하면 이벤트가 발생하고 현재 scroll 위치가 페이지에 끝에 닿았는지 판단한다. 하지만 이 경우 scroll 이벤트는 굉장히 빈번하게 발생하기 때문에 성능 최적화에 위배되는 문제가 있다. 그렇기 때문에