인프런 커뮤니티 질문&답변

꽃갈피님의 프로필 이미지
꽃갈피

작성한 질문수

React로 NodeBird SNS 만들기

인피니트 스크롤링에 관한 질문입니다.

작성

·

325

0

안녕하세요 :)

강의 7-11에서 LOAD_MAIN_POSTS_REQUEST가 중복 요청이 되어 useRef를 사용하여 해결을 하셨는데, 해시태그 페이지에서도 같은 문제가 발생해서 git에 올려놓으신 구버전(old branch) 소스코드나 강좌에서 참고하려했지만 useRef를 적용하는 것에 대한 설명이 없었습니다. 그래서 배운 내용을 스스로 적용해보던 와중에 문제가 생겨서 이렇게 질문을 남깁니다.

먼저 제가 수정한 코드는 아래와 같습니다. (제가 코드를 첨부하는데 제가 잘 다루지 못해서 그런지 javascript로 설정을 해도 계속 글씨가 제대로 보이지 않아서 굵은 글씨로 변경했습니다ㅜㅜ)

해시태그 페이지에서도 마찬가지로 LOAD_HASHTAG_POSTS_REQUEST 가 중복요청이 돼서 일단 saga에는watchLoadHashtagPosts의 takeLatest를 throttle로 수정하여 아래와 같은 코드로 바드로 바꿨습니다.

function* watchLoadHashtagPosts() { 

    yield throttle(2000, LOAD_HASHTAG_POSTS_REQUEST, loadHashtagPosts); 

}

그리고 Hashtag.js 는 useRef를 사용하여 아래와 같이 바꿨습니다.

import React, { useEffect, useCallback, useRef } from 'react';

import PropTypes from 'prop-types';

import { useDispatch, useSelector } from 'react-redux';

import { LOAD_HASHTAG_POSTS_REQUEST } from '../reducers/post';

import PostCard from '../components/PostCard';

const Hashtag = ({ tag }) => {

    const dispatch = useDispatch();

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

    const countRef = useRef([]);

    const onScroll = useCallback(() => {

        if (window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight - 300) {

            const lastId = mainPosts[mainPosts.length - 1] && mainPosts[mainPosts.length -1].id;

            if (!countRef.current.includes(lastId)) {

                if (hasMorePost) {

                    dispatch({

                        type: LOAD_HASHTAG_POSTS_REQUEST,

                        lastId,

                        data: tag,

                    })

                }

                countRef.current.push(lastId);

            }

        }

    }, [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.createdAt} post={c} />

            ))}

        </div>

    );

};

Hashtag.propTypes = {

    tag: PropTypes.string.isRequired,

};

Hashtag.getInitialProps = async (context) => { 

    const tag = context.query.tag;

    context.store.dispatch({

        type: LOAD_HASHTAG_POSTS_REQUEST,

        data: tag,

    })

    return { tag }; 

};

export default Hashtag;

그리고 버그는 아래와 같은 순서로 실행시키면 발생합니다.

1. 예를 들어 게시물이 25개 가량 있다고 가정을 합니다.

2. http://localhost:3060/hashtag/인프런 페이지에서 10개씩 게시물을 보여주는 인피니티 스크롤링을 한 번 해서 21번째 게시글의 #인프런 해시태그를 클릭합니다.

3. http://localhost:3060/hashtag/인프런 페이지가 로드될 때, 리덕스 devtools를 통해 액션어 어떻게 실행이 되는지 확인해보면

LOAD_HASHTAG_POSTS_REQUEST

LOAD_HASHTAG_POSTS_REQUEST

LOAD_HASHTAG_POSTS_SUCCESS

LOAD_HASHTAG_POSTS_SUCCESS

이런 식으로 동작을 해서 게시물을 2번 로드해서 중복된 게시물이 보이게 됩니다.

4. console.log를 작성해서 확인해보면, 위와 같은 과정으로 실행시켰을 때 Hashtag.getInitialProps에서 뿐만 아니라 onScroll이 한 번더 실행이 돼서 dispatch로 인해 LOAD_HASHTAG_POSTS_REQUEST를 요청하는 것을 확인할 수 있었습니다. 왜 onScroll이 페이지가 새로 로드가 될 때 같이 실행이 되는지 모르겠습니다.

인피니트 스크롤링을 하지 않은 상태의  최신 10개 글 내에서 해시태그를 클릭하거나, 해당 해시태그 페이지를 새로고침하면 위와 같은 버그가 발생하지 않았고, 인피니트 스크롤링을 실행한 후 생성되는 게시물의 해시태그를 클릭하면 버그가 발생합니다.

답변 8

0

꽃갈피님의 프로필 이미지
꽃갈피
질문자

알려주신대로 하니 이제 잘 돼요! :D 친절하게 알려주시고 같이 해결해주셔서 정말 감사합니다! 

선생님 덕분에 행복한 금요일 저녁을 보낼 것 같아요 :) 

선생님도 즐거운 금요일 저녁, 주말이 되길 바라겠습니다! 다시 한 번 감사합니다 :D

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

해시태그에서 다른 해시태그로 갈 때는 컴포넌트가 unmount되었다가 다시 mount되는 것이 아니라서 countRef가 유지됩니다.

따라서 useEffect에서 해시태그가 변경되었을 때 countRef를 초기화해야할 것 같습니다.

useEffect(() => {
  countRef.current = [];
}, [tag])

0

꽃갈피님의 프로필 이미지
꽃갈피
질문자

알려주신대로 if(window.scrollY)를 추가하여 중복으로 데이터를 불러오는 현상은 해결이 되었는데 인피니트 스크롤링이 되지 않습니다.

로그를 통해 확인해보니 !countRef.current.includes(lastId) 가 false여서 실행이 되지 않았는데, 해시태그를 통해 이동했을 때 countRef가 빈 배열이여야 하는데 lastId가 이미 채워져 있었습니다.

이 버그가 메인페이지(홈)에서 해시태그를 눌러서 이동하면 발생하지 않는데, 해시태그 페이지 내에서 해시태그를 다시 누르면 발생합니다.

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

window.scrollY가 0인데도 scroll 이벤트가 실행되는 것이네요.

간단하게 버그 해결하자면 if (window.scrollY)를 추가해서 window.scrollY가 0일때는 실행되지 않게 하면 될 것 같습니다.

0

꽃갈피님의 프로필 이미지
꽃갈피
질문자

입력한 순서대로 0, 559, 259 로 나옵니다.

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

hashtag.js에서 window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight - 300

이 부분

console.log(window.scrollY, document.documentElement.clientHeight, document.documentElement.scrollHeight - 300)

이렇게 기록하고 #해시태그 눌러서 해시태그 검색 페이지로 넘어가면 각각 몇이 나오나요?

0

꽃갈피님의 프로필 이미지
꽃갈피
질문자

const PostCardContent = ({ postData }) => {
    return (
        <div>
            {postData.split(/(#[^\s]+)/g).map((v=> {
                if(v.match(/#[^\s]+/)) {
                    return (
                        <Link
                            scroll={false}
                            href={{ pathname: '/hashtag', query: { tag: v.slice(1) }}}
                            as={`/hashtag/${v.slice(1)}`}
                            key={v}
                        >
                            <a>{v}</a>
                        </Link>
                    )
                }
                return v;
            })}
        </div>
    )
};

말씀해주신 부분에 scroll={false} 를 추가했는데도 같은 버그가 발생합니다. 혹시나하고 수정한 뒤 서버 재시작도 해봤는데도 그대로입니다ㅠㅠ

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

hashtag 검색으로 이동하는 Link 컴포넌트에 scroll={false} 추가해보시겠어요?

<Link scroll={false} href={...

꽃갈피님의 프로필 이미지
꽃갈피

작성한 질문수

질문하기