• 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    미해결

강의 깃허브 코드에 버그가 있습니다

20.03.13 00:20 작성 조회수 143

0

어제 인피니트 스크롤링에서 버그가 발생한다고 글을 올렸습니다. 확인해보니 강의 코드에도, nodebird.com 에도 동일한 버그가 존재하지만 두 가지 버그가 맞물려 그런 현상이 일어나지 않는 것 처럼 보입니다.

우선 getInitialProps에서 한 번, onScroll 이벤트에서 한 번, 이렇게 총 두 번씩 request - request - success - success 하여 mainPosts에 중복된 데이터가 들어가는 현상은 사이트 내 스크롤바가 어느정도 아래로 내려와있는 상태에서, 포스트들을 로드하는 다른 페이지(index, hashtag, profile)로 이동했을 때, 해당 포스트들을 로딩하는 리퀘스트를 saga에서 throttle로 받게끔 한 경우 생깁니다.

노드버드 사이트 내에서는 버그를 재현하기가 굉장히 애매합니다.

노드버드 코드에서 throttle을 적용한 곳이 watchLoadMainPosts() 밖에 없습니다. 근데 index 페이지로 이동하는 버튼은 최상단에 있습니다. 그러니 스크롤바가 내려간 상태에서 인덱스 페이지로 이동하는 방법은  다른 페이지에서 스크롤을 쭉 내린 후 뒤로가기를 통해 들어가는 방법인데요, 이게 또 브라우저에 달린 뒤로가기 버튼으로는 발생하지 않고 마우스에 달린 뒤로가기 버튼이나 마우스 제스쳐를 통한 뒤로가기시에만 발생합니다ㅜㅜ..

혹시 테스트 해보실 예정이라면 index 페이지 대신 watchLoadHashtagPosts() 코드를 throttle로 수정한 뒤에, 메인 페이지 스크롤을 쭉 내린 후 보이는 아무 해시태그나 눌러서 그 페이지로 들어가 확인하는게 더 편할 것 같습니다.

아무튼 저렇게 뒤로가기를 해서 메인 페이지로 돌아가게 되면 노드버드 페이지 콘솔에 다음과 같은 에러 로그가 찍힙니다.

이 부분은

 https://github.com/ZeroCho/react-nodebird/blob/master/ch8/front/pages/index.js

해당 코드의 16번째 줄에서 mainPosts가 비어있는지 확인하지 않아 mainPosts가 비어있는 경우, undefined.id에 접근을 해서 나는 에러입니다.

페이지로 들어갈 때 getInitialProps에서 한 번, onScroll 이벤트에서 한 번씩 디스패치를 하게 되는데, getInitialProps에서 디스패치된 리퀘스트가 리덕스 state의 mainPosts를 빈 배열로 만들고, 그 상황에서 16번째 줄이 실행되어 위에 첨부한 에러가 발생합니다.

따라서 nodebird.com 내에선 해당 에러가 catch되어 아랫부분의 dispatch가 실행되지 않아 같은 포스트들이 두 번 로드되는 상황이 일어나지 않습니다. 결과적으로 사이트 내에선 버그가 없는 것 처럼 보익 ㄱㅔ됩니다.

실제로 제로초님 깃허브 코드를 그대로 받아 undefined 버그를 해결해 테스트해보면 중복된 데이터가 들어오는 현상이 일어납니다.

중복 데이터 버그를 해결하여 공지로 올려주시거나 강의에서 throttle 쓰는 내용을 제거하는게 좋을 것 같습니다.

감사합니다.

답변 1

답변을 작성해보세요.

0

저는 다음과 같이 useEffect, useCallback의 배열에 dependencies를 정확히 기재하는 것으로 중복데이터 버그를 해결하였습니다.
데구리님도 되시나요?

import
React, { useCallback, useEffect } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { LOAD_HASHTAG_POSTS_REQUEST } from '../reducers/post';
import PostCard from '../containers/PostCard';

const Hashtag = ({ tag }) => {
const dispatch = useDispatch();

const { mainPosts, hasMorePost } = useSelector(state => state.post);

const onScroll = useCallback(() => {
if (window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight - 300) {
if (hasMorePost) {
dispatch({
type: LOAD_HASHTAG_POSTS_REQUEST,
lastId: mainPosts[mainPosts.length - 1] && mainPosts[mainPosts.length - 1].id,
data: tag,
});
}
}
}, [hasMorePost, mainPosts.length, tag]);

useEffect(() => {
window.addEventListener('scroll', onScroll);
return () => {
window.removeEventListener('scroll', onScroll);
};
}, [mainPosts.length, hasMorePost, tag]);

return (
<div>
{mainPosts.map(c => (
<PostCard key={c.id} post={c} />
))}
</div>
);
};

Hashtag.propTypes = {
tag: PropTypes.string.isRequired,
};

Hashtag.getInitialProps = async (context) => {
const { tag } = context.query;
console.log('hashtag getInitialProps', tag);
context.store.dispatch({
type: LOAD_HASHTAG_POSTS_REQUEST,
data: tag,
});
return { tag };
};

export default Hashtag;