• 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    미해결

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

24.01.02 19:43 작성 조회수 151

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)

 

답변 2

·

답변을 작성해보세요.

1

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

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

박해진님의 프로필

박해진

질문자

2024.01.02

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

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2024.01.02

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

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

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

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