[오즈의 제작소 NINJA] 리덕스 환경에서 댓글 무한 로딩 적용하기 (2)
3-(3) 무한스크롤을 위한 프론트엔드 변화
🙏 방식
이 컴포넌트를 기준으로 threshold
값 넘어가면 다음 댓글들을 로드함.
{!isDisable && (
<div className={'loading'} ref={target}>
{loading}
</div>
)}
isDisable
이 false
이면 DOM 상에 노출된다. => 가시성 관찰 (가져올 댓글 o)
isDisable
이 true
이면 DOM 상에서 지운다. => 가시성 관찰 중단 (가져올 댓글 x)
1. create observer & onIntersect handler
const onIntersect = (entries, observer) => {
if (entries[0].isIntersecting) {
dispatch(
loadAllComments({ id: postData.id, page: page, comments: comments }),
);
observer.unobserve(target.current); //target.current가 변경 되면
}
};
entries[0].isIntersecting
은 교차되었는지에 대한 boolean
값을 갖는다. 교차되었다면,
loadAllComments
액션을 수행한다. loadAllComments
이지만 page값 부터 10개의 댓글을 가져오도록 변경하였다.
observer.unobserver(target.current)
는 현재 타겟에 대한 감시를 중단한다.
useEffect(() => {
if (page % 10 === 0 && page !== 0) {
const observer = new IntersectionObserver(
(entries, observer) => onIntersect(entries, observer),
{ threshold: 1 },
);
// 갱신 해주지 않으면 이전의 page에 접근해서 요청함.
if (target.current) {
observer.observe(target.current);
}
return () => observer && observer.disconnect();
} else {
setIsDisable(true);
}
}, [page]);
page값은 댓글의 길이 값을 갖고있다. ( 지금 댓글의 길이 다음 댓글 부터 가져와야하므로 )
만약 댓글의 길이(=page) 를 10으로 나눈 나머지 값이 0이 아니라면 모든 댓글을 다 가져온 것이므로 setIsDisable(true)
을 통해 감시하던 객체를 없앤다.
10으로 나눈 나머지 값이 0이라면 아직 가져올 댓글이 있거나, 마지막 댓글인 것이므로 감시를 계속한다. onIntersect()
에서 갱신된 page값을 참조할 수 있도록 새로운 observer
를 만든다.
❓ page값이 갱신될 때 마다 옵저버를 새롭게 new 해주면 계속 옵저버들이 쌓이는 걸까? 참조가 끊겨 가비지가 될 수 있음. => 확인 요망 ❗️
2. update page state
useEffect(() => {
setPage(comments.length);
}, [comments.length]);
comments.length
값을 의존성 배열안에 넣어준다. 값이 변하면 새로운 댓글들을 로드한 것이므로 setPage(comments.length)
해주어 값을 갱신해준다.
3. redux loadAllCommentsSaga
export const loadAllComments = createAction(LOAD_ALL_COMMENTS);
function* loadAllCommentsSaga(action) {
yield put(startLoading(LOAD_ALL_COMMENTS));
try {
const loadAllComments = yield call(
commentsAPI.getCommentsByPostId,
action.payload,
);
yield put({
type: LOAD_ALL_COMMENTS_SUCCESS,
payload: [
...action.payload.comments,
...loadAllComments.data.allComments,
],
});
} catch (e) {
yield put({
type: LOAD_ALL_COMMENTS_FAILURE,
payload: e,
error: true,
});
}
yield put(finishLoading(LOAD_ALL_COMMENTS));
}
yield put({
type: LOAD_ALL_COMMENTS_SUCCESS,
payload: [
...action.payload.comments,
...loadAllComments.data.allComments,
],
});
기존의 댓글 배열에 가져온 댓글 배열을 이어서 comment reducer
에게 전달.
[LOAD_ALL_COMMENTS_SUCCESS]: (state, { payload }) => {
return {
...state,
comments: payload.map((comment) => ({
...comment,
Comments: comment.Comments.map((reply) => ({
...reply,
isEditClicked: false,
isMenuClicked: false,
})),
isEditClicked: false,
isMenuClicked: false,
isClicked: false,
})),
error: null,
};
immer
를 사용하지않아 더러운 모습이다......
action.payload
로 전달된 댓글 배열들을 리덕스 상태에 주입한다.
4. 느낀점
- onIntersect에서 state를 사용하는 경우 state값이 갱신될 때 마다 onIntersect 함수를 다시로드 해주어야함. 이렇게 안하면 과거 page값을 참조.
5. Reference
Author And Source
이 문제에 관하여([오즈의 제작소 NINJA] 리덕스 환경에서 댓글 무한 로딩 적용하기 (2)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@rat8397/오즈의-제작소-NINJA-리덕스-환경에서-댓글-무한-로딩-적용하기-2저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)