• 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    미해결

무한정 back으로부터 post 데이터를 불러와요!

21.12.26 20:38 작성 조회수 108

0

안녕하세요 zerocho 선생님...

다른게 아니라 이 부분에서 아주 크나큰 문제에 맞닥뜨려 

작업을 못하고 있습니다. 

 

pages/index.js에서  useEffect를 사용해서 

첫 페이지에 오면 로그인 유무를 판단하고 

또 기존에 있던 게시글을 불러와야 하는것을 잘 아는데

 

문제는 로그인할 경우에는 딱 한번만 LOAD_MY_INFO_REQUEST를 잘 수행하는데  LOAD_POST_REQUEST를하는순간 무한 응답을 합니다. 

 

 

 

post man에서 받아온 데이터를 다음과 같습니다.

 

사실 저는 springboot를 back으로 사용하고 있는데 

 

이유는 JPA를 좀 사용해보고 싶어서 였습니다.

 

next.js를 아예 안쓰는것이 나앗던 것 같지만 처음에 강의를 접하고 할때는 아무것도 몰라서...  무진 후회중.. 그냥따라할걸...

 

하여간... 기존의 데이터도 이런 식으로 받아오는데 문제는 

무한 응답을 요청하니까 도대체 어디서 잘못된건지 모르겠다는 것입니다. ㅠㅠ 제발좀 도와주십시오.;.. 

 

pages/index.js

import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import AppLayout from "../components/AppLayout";
import PostCard from "../components/middleComponent/Post/PostCard";
import PostForm from "../components/middleComponent/Post/PostForm";
import { LOAD_POST_REQUEST } from "../reducers/post";
import { LOAD_MY_INFO_REQUEST } from "../reducers/user";

const Home = () => {
    const dispatch = useDispatch();
    const { me } = useSelector((state) => state.user);
    const { mainPosts, hasMorePost, loadPostLoading } = useSelector((state) => state.post);

    useEffect(() => {
        console.log("useEffect in index.js")
        dispatch({
            type: LOAD_MY_INFO_REQUEST
        });
        // dispatch({
        //     type: LOAD_POST_REQUEST,
        // });
    }, [hasMorePost, loadPostLoading]);

    useEffect(() => {
        function onScroll() {
            if (window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight -  300){
                if (hasMorePost && !loadPostLoading) {
                    dispatch({
                        type: LOAD_POST_REQUEST,
                    });
                }
            }
        }
        window.addEventListener('scroll', onScroll);
        return () => {
            window.removeEventListener('scroll', onScroll);
        }
    }, []);
    console.log(mainPosts);
    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 produces, { produce } from 'immer';
import faker from 'faker';
import { ConsoleSqlOutlined } from '@ant-design/icons';
export const initialState = {
    mainPosts: [],
    imagePaths: [],
    hasMorePost: true,
    loadPostLoading: false,
    loadPostDone: false,
    loadPostError: null,
    addPostLoading: false,
    addPostDone: false,
    addPostError: null,
    addCommentLoading: false,
    addCommentDone: false,
    addCommentError: null,
    removePostLoading: false,
    removePostDone: false,
    removePostError: 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: faker.image.imageUrl(),
    }],
    Comments: [{
        User: {
            id: shortId.generate(),
            nickname: faker.name.findName()
        },
        content: faker.lorem.sentence(),
    }],
}));

export const LOAD_POST_REQUEST = 'LOAD_POST_REQUEST';
export const LOAD_POST_SUCCESS = 'LOAD_POST_SUCCESS';
export const LOAD_POST_FAILURE = 'LOAD_POST_FAILURE';

export const ADD_POST_REQUEST = 'ADD_POST_REQUEST';
export const ADD_POST_SUCCESS = 'ADD_POST_SUCCESS';
export const ADD_POST_FAILURE = 'ADD_POST_FAILURE';

export const ADD_COMMENT_REQUEST = 'ADD_COMMENT_REQUEST';
export const ADD_COMMENT_SUCCESS = 'ADD_COMMENT_SUCCESS';
export const ADD_COMMENT_FAILURE = 'ADD_COMMENT_FAILURE';

export const REMOVE_POST_REQUEST = 'REMOVE_POST_REQUEST';
export const REMOVE_POST_SUCCESS = 'REMOVE_POST_SUCCESS';
export const REMOVE_POST_FAILURE = 'REMOVE_POST_FAILURE';

export const ADD_POST_TO_ME = 'ADD_POST_TO_ME';
export const REMOVE_POST_OF_ME = 'REMOVE_POST_OF_ME';

export const addPost = (data) => ({
    type: ADD_POST_REQUEST,
    data
})

export const addComment = (data) => ({
    type: ADD_COMMENT_REQUEST,
    data
})

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

// const dummyComment = (data) => ({
//     id: shortId.generate(),
//     content: data,
//     User: {
//         id: 1,
//         nickname: 'thelovedaejeon',
//     },
// })

//이전 상태를 action을 통해 다음 상태로 만들어 내는 함수 (불변성을 지키면서)
const reducer = (state = initialState, action) => {
    return produce (state, (draft) => {
        switch (action.type){
            case LOAD_POST_REQUEST:
                draft.loadPostLoading = true;
                draft.loadPostDone= false;
                draft.loadPostError= null;
                break;
            case LOAD_POST_SUCCESS:
                draft.loadPostLoading = false;
                draft.loadPostDone= true;
                draft.mainPosts = action.data.concat(draft.mainPosts);
                draft.hasMorePost = false;
                break;
            case LOAD_POST_FAILURE:
                draft.loadPostLoading = false;
                draft.loadPostError = action.error;
                break;
            case ADD_POST_REQUEST:
                draft.addPostLoading = true;
                draft.addPostDone= false;
                draft.addPostError= null;
                break;
            case ADD_POST_SUCCESS:
                draft.addPostLoading = false;
                draft.addPostDone= true;
                draft.mainPosts.unshift(dummyPost(action.data));
                break;
            case ADD_POST_FAILURE:
                draft.addPostLoading = false;
                draft.addPostError = action.error;
                break;
            case REMOVE_POST_REQUEST:
                draft.removePostLoading = true;
                draft.removePostDone = false;
                draft.removePostError = null;
                break;
            case REMOVE_POST_SUCCESS:
                draft.removePostLoading = false;
                draft.removePostDone = true;
                draft.mainPosts = draft.mainPosts.filter((v) => v.id !== action.data);
                break;
            case REMOVE_POST_FAILURE:
                draft.removePostLoading = false;
                draft.removePostError = action.error;
                break;
            case ADD_COMMENT_REQUEST:
                draft.addCommentLoading = true;
                draft.addCommentDone = false;
                draft.addCommentError = null;
                break;
            case ADD_COMMENT_SUCCESS:{
                const post = draft.mainPosts.find((v) => v.id === action.data.postId);
                post.Comments.unshift(dummyComment(action.data.content));
                draft.addCommentLoading = false;
                draft.addCommentDone = true;
                break;
                // const postIndex = state.mainPosts.findIndex((v) => v.id === action.data.postId);
                // const post = { ...state.mainPosts[postIndex] };
                // post.Comments = [dummyComment(action.data.content), ...post.Comments];
                // const mainPosts = [...state.mainPosts];
                // mainPosts[postIndex] = post;
                // return {
                //   ...state,
                //   mainPosts,
                //   addCommentLoading: false,
                //   addCommentDone: true,
                // };
            }
            case ADD_COMMENT_FAILURE:
                draft.addCommentLoading = false;
                draft.addCommentError = action.error;
                break;
            default:
                break;
        }
    });
};

export default reducer;

 

sagas/post.js

import { delay, fork, all, takeLatest, put, call} from "redux-saga/effects";
import shortId from "shortid";
import axios from 'axios';
// import Axios from 'axios';
// import qs from 'query-string';
import Cookies from 'universal-cookie';
import {
    ADD_COMMENT_FAILURE,
    ADD_COMMENT_REQUEST,
    ADD_COMMENT_SUCCESS,
    ADD_POST_FAILURE,
    ADD_POST_REQUEST,
    ADD_POST_SUCCESS,
    ADD_POST_TO_ME,
    generateDummyPost,
    LOAD_POST_FAILURE,
    LOAD_POST_REQUEST,
    LOAD_POST_SUCCESS,
    REMOVE_POST_FAILURE,
    REMOVE_POST_REQUEST,
    REMOVE_POST_SUCCESS
} from "../reducers/post";
import { REMOVE_POST_OF_ME } from "../reducers/user";
const cookies = new Cookies();
function addPostAPI(data) {
    const accessToken = cookies.get("accessToken");
    const userEmail = cookies.get("userEmail");
    const newObj = {
        description : data,
        email : userEmail
    }
    return axios.post('/auth/post', newObj,{
        headers:{
            'Authorization': `Bearer ${accessToken}`,
            "Content-Type": "application/json"
        }
    });
}

function* addPost(action) {
    try {
        const result = yield call(addPostAPI, action.data);
        yield put({
            type: ADD_POST_SUCCESS,
            data: {
                id : result.data.postId,
                content: action.data
            }
        })
        yield put({
            type: ADD_POST_TO_ME,
            data: result.data.postId,
        })
    } catch (error) {
        console.log(error);
        yield put({
            type: ADD_POST_FAILURE,
            data: error.data
        })
    }
}

function loadPostAPI(data) {
    return axios.get('/api/posts');
}

function* loadPost(action) {
    try {
        const result = yield call(loadPostAPI);
        console.log(result);
        console.log(result.data);
        yield put({
            type: LOAD_POST_SUCCESS,
            data: result.data.result,
        });
    } catch (error) {
        console.log(error);
        yield put({
            type: LOAD_POST_FAILURE,
            data: error.data
        })
    }
}

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

function* removePost(action) {
    try {

        delay(1000);
        // const result = yield call(addPostAPI, action.data);
        const id = shortId.generate();
        yield put({
            type: REMOVE_POST_SUCCESS,
            data: action.data
           
        });
        yield put({
            type: REMOVE_POST_OF_ME,
            data: action.data
        })
    } catch (error) {
        yield put({
            type: REMOVE_POST_FAILURE,
            data: error.data
        })
    }
}

function addCommentAPI(data) {
    return axios.post('/api/post/${data.postId}/comment', data);
}

function* addComment(action) {
    try {
        delay(1000);
        // const result = yield call(addPostAPI, action.data);
        yield put({
            type: ADD_COMMENT_SUCCESS,
            data: action.data
        })
    } catch (error) {
        yield put({
            type: ADD_COMMENT_FAILURE,
            data: error.data
        })
    }
}

function* watchAddPost(){
    yield takeLatest(ADD_POST_REQUEST, addPost); // 첫번째것만 하고 싶으면 takeLeading
}

function* watchLoadPost(){
    yield takeLatest(LOAD_POST_REQUEST, loadPost); // 첫번째것만 하고 싶으면 takeLeading
}

function* watchRemovePost(){
    yield takeLatest(REMOVE_POST_REQUEST, removePost); // 첫번째것만 하고 싶으면 takeLeading
}

function* watchAddComment(){
    yield takeLatest(ADD_COMMENT_REQUEST, addComment); // 첫번째것만 하고 싶으면 takeLeading
}

export default function* postSaga(){
    yield all([
        fork(watchLoadPost),
        fork(watchAddPost),
        fork(watchRemovePost),
        fork(watchAddComment),
    ])
};

 

 

답변 1

답변을 작성해보세요.

1

useEffect의 []에서 hasMorePost랑 isPostLoading을 빼세요.

아 진짜... 너무감사합니다... 정말 좋은 강의 잘 듣고있습니다. ㅠㅠ