강의

멘토링

로드맵

Inflearn brand logo image

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

Sim Gyuhun님의 프로필 이미지
Sim Gyuhun

작성한 질문수

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

게시글 불러오기

post 에서 작성 후 mainPosts.map 에서 key={post.id} 가 undefined 로 나옵니다.

작성

·

437

·

수정됨

0

에러메세지:ADD_POST_SUCCESS 까지 잘 되었고 content 에 id 도 잘 들어가 있는걸로 보입니다. 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";
import { LOAD_USER_REQUEST } from "../reducers/user";

const Home = () => {
  const me = useSelector((state) => state.user.me);
  const { mainPosts, hasMorePosts, isLoadingPosts } = useSelector(
    (state) => state.post
  );
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch({
      type: LOAD_USER_REQUEST,
    });
    dispatch({
      type: LOAD_POSTS_REQUEST,
    });
  }, []);

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

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

export default Home;

reducers/post.js

import produce from "immer";

export const initialState = {
  mainPosts: [],
  imagePaths: [],
  hasMorePosts: true,
  isAddingPost: false,
  isAddedPost: false,
  isAddPostErr: null,
  isRemovingPost: false,
  isRemovedPost: false,
  isRemovePostErr: null,
  isAddingComment: false,
  isAddedComment: false,
  isAddCommentErr: null,
  isRemovingComment: false,
  isRemovedComment: false,
  isRemoveCommentErr: null,
  isLoadingPosts: false,
  isLoadedPosts: false,
  isLoadPostsErr: null,
};

export const LOAD_POSTS_REQUEST = "LOAD_POSTS_REQUEST";
export const LOAD_POSTS_SUCCESS = "LOAD_POSTS_SUCCESS";
export const LOAD_POSTS_FAILURE = "LOAD_POSTS_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 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_COMMENT_REQUEST = "ADD_COMMENT_REQUEST";
export const ADD_COMMENT_SUCCESS = "ADD_COMMENT_SUCCESS";
export const ADD_COMMENT_FAILURE = "ADD_COMMENT_FAILURE";

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

const reducer = (state = initialState, action) => {
  return produce(state, (draft) => {
    switch (action.type) {
      case ADD_POST_REQUEST:
        draft.isAddingPost = true;
        draft.isAddedPost = false;
        draft.isAddPostErr = null;
        break;
      case ADD_POST_SUCCESS:
        draft.isAddingPost = false;
        draft.mainPosts.unshift(action.data);
        draft.isAddedPost = true;
        break;
      case ADD_POST_FAILURE:
        draft.isAddingPost = false;
        draft.isAddedPost = false;
        draft.isAddPostErr = action.error;
        break;

      case REMOVE_POST_REQUEST:
        draft.isRemovingPost = true;
        draft.isRemovedPost = false;
        draft.isRemovePostErr = null;
        break;
      case REMOVE_POST_SUCCESS:
        draft.isRemovingPost = false;
        draft.mainPosts = state.mainPosts.filter((v) => v.id !== action.data);
        draft.isRemovedPost = true;
        draft.isRemovePostErr = null;
        break;

      case REMOVE_POST_FAILURE:
        draft.isRemovingPost = false;
        draft.isRemovedPost = false;
        draft.isRemovePostErr = action.error;
        break;
      case ADD_COMMENT_REQUEST:
        draft.isAddingComment = true;
        draft.isAddedComment = false;
        draft.isAddCommentErr = null;
        break;
      case ADD_COMMENT_SUCCESS:
        draft.isAddingComment = false;
        const post = draft.mainPosts.find((v) => v.id === action.data.PostId);
        post.Comments.unshift(action.data);
        draft.isAddedComment = true;
        break;
      case ADD_COMMENT_FAILURE:
        draft.isAddingComment = false;
        draft.isAddedComment = false;
        draft.isAddCommentErr = action.error;
        break;

      case LOAD_POSTS_REQUEST:
        draft.isLoadingPosts = true;
        draft.isLoadedPosts = false;
        draft.isLoadPostsErr = null;
        break;
      case LOAD_POSTS_SUCCESS:
        draft.isLoadingPosts = false;
        draft.mainPosts = draft.mainPosts.concat(action.data);
        draft.isLoadedPosts = true;
        break;
      case LOAD_POSTS_FAILURE:
        draft.isLoadingPosts = false;
        draft.isLoadedPosts = false;
        draft.isLoadPostsErr = action.error;
        break;

      default:
        break;
    }
  });
};

export default reducer;

sagas/post.js

import { delay, all, fork, put, takeLatest, call } from "redux-saga/effects";
import axios from "axios";
import {
  ADD_POST_REQUEST,
  ADD_POST_SUCCESS,
  ADD_POST_FAILURE,
  ADD_COMMENT_FAILURE,
  ADD_COMMENT_SUCCESS,
  ADD_COMMENT_REQUEST,
  REMOVE_POST_REQUEST,
  REMOVE_POST_SUCCESS,
  REMOVE_POST_FAILURE,
  LOAD_POSTS_REQUEST,
  LOAD_POSTS_SUCCESS,
  LOAD_POSTS_FAILURE,
} from "../reducers/post";
import { ADD_POST_TO_ME, REMOVE_POST_FROM_ME } from "../reducers/user";

function addPostAPI(data) {
  return axios.post(
    "/post",
    { content: data },
    {
      withCredentials: true,
    }
  );
}

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

function removePostAPI(data) {
  return axios.delete("/post", data);
}

function* removePost(action) {
  try {
    yield delay(1000);
    yield put({
      type: REMOVE_POST_SUCCESS,
      data: action.data,
    });
    yield put({
      type: REMOVE_POST_FROM_ME,
      data: action.data,
    });
  } catch (err) {
    yield put({
      type: REMOVE_POST_FAILURE,
      error: err.response.data,
    });
  }
}

function addCommentAPI(data) {
  return axios.post(`/post/${data.postId}/comment`, data); //POST /post/1/comment
}

function* addComment(action) {
  try {
    const result = yield call(addCommentAPI, action.data);
    yield put({ type: ADD_COMMENT_SUCCESS, data: result.data });
  } catch (err) {
    console.log(err);
    yield put({
      type: ADD_COMMENT_FAILURE,
      error: err,
    });
  }
}

function loadPostsAPI() {
  return axios.get(`/posts`);
}

function* loadPosts(action) {
  try {
    const result = yield call(loadPostsAPI, action.data);
    yield put({ type: LOAD_POSTS_SUCCESS, data: result.data });
  } catch (err) {
    console.log(err);
    yield put({
      type: LOAD_POSTS_FAILURE,
      error: err.response.data,
    });
  }
}

function* watchAddPost() {
  yield takeLatest(ADD_POST_REQUEST, addPost);
}

function* watchRemovePost() {
  yield takeLatest(REMOVE_POST_REQUEST, removePost);
}

function* watchAddComment() {
  yield takeLatest(ADD_COMMENT_REQUEST, addComment);
}

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

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

routes/posts.js

const express = require("express");

const { Post, Image, User, Comment } = require("../models");

const router = express.Router();

router.get("/", async (req, res, next) => {
  // GET /posts
  try {
    const posts = await Post.findAll({
      limit: 10,
      order: [
        ["createdAt", "DESC"],
        [Comment, "createdAt", "DESC"],
      ],
      include: [
        {
          model: User,
          attributes: ["id", "nickname"],
        },
        {
          model: Image,
        },
        {
          model: Comment,
          include: [{ model: User, attributes: ["id", "nickname"] }],
        },
      ],
    });
    res.status(200).json(posts);
  } catch (err) {
    console.error(err);
    next(err);
  }
});

module.exports = router;

sql 테이블도 잘 들어가있고, 새로 고침 하면 포스팅은 잘 되어 있습니다.

답변 1

0

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

post가 undefined인 것이고요. mainPosts state를 봐보세요. 제가 봤을 땐 ADD_POST_TO_ME인 것 같습니다.

Sim Gyuhun님의 프로필 이미지
Sim Gyuhun

작성한 질문수

질문하기