inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

[리뉴얼] React로 NodeBird SNS 만들기

인피니트 스크롤링 적용하기

인피니트 스크롤링 적용시 LOAD_POST_REQUEST 두번 찍히는 문제

355

박해진

작성한 질문수 12

0

안녕하세요 선생님

 

상황)
인피니트 스크롤링 적용시 LOAD_POST_REQUEST 두번 찍히는 상황인데 이거의 원인과 해결방법을 어떻게 찾을 수 있을까요? loadPostsLoading과 throttle을 적용했는데도 2번씩 실행되는 상황입니다.

redux)

스크린샷 2024-01-02 오후 7.31.38.png스크린샷 2024-01-02 오후 7.31.34.png스크린샷 2024-01-02 오후 7.28.11.png


작성한 코드) 10,000 자이하만 적을 수 있어서 LOAD_POSTS_REQUEST 관련 코드만 올립니다..!!
pages/index.js

import React, { useEffect } from 'react';
import {useDispatch, useSelector} from 'react-redux';
import AppLayout from '../components/AppLayout';
import PostCard from '../components/PostCard';
import PostForm from '../components/PostForm';
import {LOAD_POSTS_REQUEST} from '../reducers/post';
const Home = () => {
    const dispatch = useDispatch();
    const { me } = useSelector((state) => state.user);
    const { mainPosts, hasMorePosts, loadPostsLoading } = useSelector((state) => state.post);

    useEffect(() => {
        dispatch({
            type: LOAD_POSTS_REQUEST,
        });
    }, []);
    useEffect(() => {
        function onScroll() {
            if(window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight-300) {
                if(hasMorePosts && !loadPostsLoading) {
                    dispatch({
                        type: LOAD_POSTS_REQUEST,
                    });
                }
            }
        }
        window.addEventListener('scroll', onScroll);
        return () => {
            window.removeEventListener('scroll', onScroll);
        };
    }, [hasMorePosts, loadPostsLoading]);

    return (
        <AppLayout>
            {me && <PostForm />}
            {mainPosts.map((post) => <PostCard key={post.id} post={post} />)}
        </AppLayout>
    );
};
export default Home;

reducers/post.js

import shortId from 'shortid';
import {produce} from 'immer';
import faker from 'faker';

export const initialState = {
    mainPosts:[],
    imagePaths: [], //게시물 저장 경로
    hasMorePosts: true,

    loadPostsLoading: false, //게시글 로드 완료시 true
    loadPostsDone: false,
    loadPostsError: null,

}
export const generateDummyPost = (number) => Array(number).fill().map(() => ({
    id: shortId.generate(),
    User: {
        id: shortId.generate(),
        nickname: faker.name.findName()
    },
    content: faker.lorem.paragraph(),
    Images: [{
        src: 'https://cdn.pixabay.com/photo/2017/07/25/01/22/cat-2536662_1280.jpg' //faker.image.imageUrl(640, 480, true), lorempixel.com 고장나서 임시로
    }],
    Comments: [{
        User: { 
            id:shortId.generate(),
            nickname:faker.name.findName(),
        },
        content:faker.lorem.sentence(),
    }],
}));
export const LOAD_POSTS_REQUEST = 'LOAD_POSTS_REQUEST';
export const LOAD_POSTS_SUCCESS = 'LOAD_POSTS_SUCCESS';
export const LOAD_POSTS_FAILURE = 'LOAD_POSTS_FAILURE';


const dummyPost = (data) => ({
    id: data.id,
    content: data.content,
    User: {
        id:1,
        nickname:'해지니',
    },
    Images: [],
    Comments: [],
});

const dummyComment = (data) => ({
    id: shortId.generate(),
    content: data,
    User: {
        id: 1,
        nickname: '제로초'
    },
});

const reducer = (state = initialState, action) => produce(state, (draft) => {
    switch(action.type){
        case LOAD_POSTS_REQUEST:
            draft.loadPostsLoading = true;
            draft.loadPostsDone = false;
            draft.loadPostsError = null;
            break;

        case LOAD_POSTS_SUCCESS:
            draft.loadPostsLoading = false;
            draft.loadPostsDone = true;
            draft.mainPosts = action.data.concat(draft.mainPosts);
            draft.hasMorePosts = draft.mainPosts.length < 50;
            break;

        case LOAD_POSTS_FAILURE:
            draft.loadPostsLoading = false;
            draft.loadPostsError = action.error;
            break;
            
        default:
            break;
    }
});

export default reducer; 

sagas/post.js

import { all, fork, takeLatest, put, delay, throttle } from 'redux-saga/effects';
import axios from 'axios';
import shortId from 'shortid';
import { 
    LOAD_POSTS_REQUEST, LOAD_POSTS_SUCCESS, LOAD_POSTS_FAILURE,
    generateDummyPost,
} from '../reducers/post';

function loadPostsAPI(data){
    return axios.get('/api/post', data);
}

function* loadPosts(action) {
    try{
        // const result = yield call(loadPostsAPI, action.data);
        yield delay(1000);
        yield put({
            type: LOAD_POSTS_SUCCESS,
            data:generateDummyPost(10)
        });
    } catch(err) {
        yield put({
            type: LOAD_POSTS_FAILURE,
            data: err.response.data
        });
    }
}

function*  watchLoadPosts(){
    yield throttle(5000, LOAD_POSTS_REQUEST, loadPosts);
}

export default function* postSaga() {
    yield all([
        fork(watchLoadPosts)
    ]);
}


사용중인 OS) macOS (Apple M1 Pro)

 

react redux node.js express next.js

답변 2

1

제로초(조현영)

이 부분은 제 깃헙 intersectionObserver 폴더에 있는 intersectionObserver 코드를 쓰시는 게 좋습니다. 좀 더 현대적인 방법입니다.

나중에 실제 데이터 연걀하시고나서 변경하시면 됩니다.

0

박해진

intersection 폴더 확인했습니당! 데이터 연결 후 다시 해보겠습니당! 감사합니다! !

0

인프런 AI 인턴

안녕하세요, 인프런 AI 인턴입니다.

인피니트 스크롤 기능 구현 시 LOAD_POST_REQUEST가 중복 호출되는 문제에 대해 궁금하신 부분이 있으신 것 같습니다. 이와 유사한 질문에 대한 답변이 인프런 게시판에 존재하는데요, 선생님께서 이미 여러 경우의 문제 상황에 대해 답변을 하셨으니 참고하시면 좋을 것 같습니다.

관련된 질문과 답변 링크를 아래에 첨부하겠습니다. 해당 링크의 내용을 살펴보시면 문제 해결에 도움이 되실 겁니다.

위의 게시글들을 통해 문제의 원인과 해결 방법에 대한 힌트를 얻으실 수 있을 것입니다.

넥스트 버젼 질문

0

78

2

로그인시 401 Unauthorized 오류가 뜹니다

0

89

1

무한 스크롤 중 스크롤 튐 현상

0

175

1

특정 페이지 접근을 막고 싶을 때

0

103

2

createGlobalStyle의 위치와 영향범위

0

96

2

인라인 스타일 리렌더링 관련

0

91

2

vsc 에서 npm init 설치시 오류

0

146

2

nextjs 15버전 사용 가능할까요?

0

158

1

화면 새로고침 문의

0

121

1

RTK에서 draft, state 차이가 있나요?

0

153

2

Next 14 사용해도 될까요?

0

452

1

next, node 버전 / 폴더 구조 질문 드립니다.

0

349

1

url 오류 질문있습니다

0

211

1

ssh xxxxx로 우분투에 들어가려니까 port 22: Connection timed out

0

373

1

sudo certbot --nginx 에러

0

1275

2

Minified React error 콘솔에러 (hydrate)

0

470

1

카카오 공유했을 때 이전에 작성했던 글이 나오는 버그

0

247

1

프론트서버 배포 후 EADDRINUSE에러 발생

0

327

1

npm run build 에러

0

518

1

front 서버 npm run build 중에 발생한 에러들

0

382

1

서버 실행하고 브라우저로 들어갔을때 404에러

0

338

2

css 서버사이드 랜더링이 적용되지 않아서 문의 드립니다.

0

288

1

팔로워 3명씩 불러오고 데이터 합쳐주는걸로 바꾸고 서버요청을 무한으로하고있습니다.

0

239

2

해시태그 검색에서 throttle에 관해 질문있습니다.

0

201

1