codestates / codestates/art-ground
[Error Handling Log] server-side 부담을 최소화 한 무한스크롤 / 박지영
- Dominant language
- JavaScript
- Stars
- 7
- Forks
- 9
- PR merge metrics
- No merged PRs in 30d
Description
### **어떤 에러인가요?**
https://user-images.githubusercontent.com/83934037/135573501-8bf3ffba-b078-4538-90f9-372f8b35feb5.mov
무한스크롤 기능 구현 시, 랜더링 뿐만 아니라 앱의 성능을 고려하여
스크롤 할 때마다 서버쪽에 자꾸 전체 데이터를 받아오는 axios GET 요청을 보내는 것을 방지하고 싶었다.
현재 서버에서 클라이언트로 데이터를 분절시켜서 보내주는 건 구현이 안 되어 있다.
(서버가 axios GET 요청을 받으면 전체 데이터를 보내주고 있는 상황)
따라서 매번 스크롤 할 때마다 프론트에서 전체데이터를 받아서 3개씩 잘라서 보여준들, 진정한 무한스크롤 기능 구현이 아니라고 생각되었다.
성능을 고려 안 할 수 없기 때문에 이 부분을 수정해주었다.
### **에러 핸들링 방법**
- 무한 스크롤 기능 구현한 방식
- 서버에 가는 부담을 최소화 하기 위하여, 댓글 데이터를 받는 axios GET요청을 최초 1번만 보내기
- 그렇게 되면 상태값이 2개 필요함.(랜더링이 되는 배열 `replyList`, 랜더링 안 되고 숨겨져 있는 배열 `hiddenReplyList`)
- 스크롤 시 `hiddenReplyList` —> `replyList` 로 배열의 요소가 일정개수만큼(3개) 옮겨가는 것과 같은 효과를 내는게 포인트.(`replyList`에는 3개 더해주고, `hiddenReplyList`에는 3개만큼 빼준다. 각각 상태 불변성 유지를 위하여 concat, slice 메소드 사용. )
- `replyList`, `hiddenReplyList` 배열의 길이는 스크롤 할 때마다 바뀜. 고정된 총 배열 길이(총 댓글 수)를 랜더링하기 위해 상태값을 1개 더 생성하여 axios GET요청 바로 직후에 따로 상태업뎃해줌.(`replyCount`)
- `isLoading` 상태값을 하나 더 만들어, 데이터 fetch 해오는 전 후로 true—> false 값으로 전환해주었다. 로딩값이 true일때는 하단에 로딩스피너를 랜더링하고 false로 바뀌면 추가된 댓글이 보여진다.(setTimeout 함수로 로딩시간 0.7초 텀을 둠)
- `isLoading` 상태값을 useCallback 내 함수(스크롤 이벤트)가 호출되는 의존성 배열 값으로 사용하였다.
```js
const [replyList, setReplyList] = useState([]); //랜더링할 데이터(스크롤할 때마다 +)
const [hiddenReplyList, setHiddenReplyList] = useState([]); //랜더링하기 전 숨겨놓는 데이터(스크롤 할 때마다 -)
const [replyCount, setReplyCount] = useState([]); //리뷰 개수 랜더링용(스크롤에 상관없이 고정)
const [isLoading, setIsLoading] = useState(true);
const [rerender, setRerender] = useState(false);
const fetchMoreData = async () => {
if(hiddenReplyList.length !== 0){ //안 보여준 댓글이 남아있을 때만
setIsLoading(true);
setTimeout(()=> {
setReplyList(replyList.concat(hiddenReplyList.slice(0, 3)));
setHiddenReplyList(hiddenReplyList.slice(3));
setIsLoading(false);
}, 700)
}
}
const _infiniteScroll = useCallback(()=> {
let scrollHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
let scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
let clientHeight = document.documentElement.clientHeight;
scrollHeight -= 100;
if(scrollTop+clientHeight >= scrollHeight && isLoading === false){
fetchMoreData();
}
}, [isLoading])
const getFetchData = async() => { //해당 전시회의 댓글(배열) GET요청. 페이지최초랜더링(+댓글 등록/삭제)때에만 작동
setIsLoading(true);
let result = await getReplyList(reviewSelected.id);
setReplyCount(await getReplyList(reviewSelected.id));//전체 댓글 개수 랜더링
setReplyList(result.slice(0, 3)); //최초에 3개만 보여주고
result = result.slice(3); //보여준 3개 제외한 나머지만 추려서
setHiddenReplyList(result); //상태값에 저장
setIsLoading(false);
}
useEffect(() => { //해당 전시회의 댓글(배열) GET요청. 페이지최초랜더링(+댓글 등록/삭제)때에만 작동
setTimeout(()=> {
getFetchData();
}, 100)
}, [rerender])
useEffect(()=> { //스크롤 이벤트 감지
window.addEventListener('scroll', _infiniteScroll, true);
return () => window.removeEventListener('scroll', _infiniteScroll, true);
}, [_infiniteScroll])
// 랜더링 파트
총 {replyCount.length}개
{replyList.map(el =>
)}
{isLoading ?
: null}
```
### **에러 핸들링을 위해 참고한 레퍼런스 링크**
https://velog.io/@jerrrry/React-Infinite-Scroll-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.