강의

멘토링

커뮤니티

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

br님의 프로필 이미지
br

작성한 질문수

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

오류가 많은거 같습니다ㅠㅠ

작성

·

201

0

이게 뭔가요...ㅠ

첨보는건데 js파일 분할하면서 꼬인건지 설치가 잘못된건지 모르겠어요

 

PostCardContent.js 파일에 postData?.split ~ 하면 아래 에러는 없어지는데 위에 오류 뜹니다

reducers/index.js

import {HYDRATE} from 'next-redux-wrapper';
import {combineReducers} from 'redux';
import user from './user';
import post from './post';

// (이전상태, 액션) => 다음상태
const rootReducer = combineReducers({
    index: (state = {}, action) => {
    switch (action.type) {
        case HYDRATE:
            console.log('HYDRATE', action);
            return {...state, ...action.payload};
            
        default:
            return state;
        }
    },
    user,
    post
});

export default rootReducer;

 

reducers/post.js

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

export const initialState = {
        mainPosts: [{
        id: 1,
        User: {
            id: 1,
            nickname: 'z',
        },
        content: '첫 번째 게시글 #해시태그 #익스프레스',
        Images: [{
            id: shortId.generate(),
            src: 'https://bookthumb-phinf.pstatic.net/cover/137/995/13799585.jpg?udate=20180726',
        }, {
            id: shortId.generate(),
            src: 'https://gimg.gilbut.co.kr/book/BN001998/rn_view_BN001998.jpg',
        }, {
            id: shortId.generate(),
            src: 'https://gimg.gilbut.co.kr/book/BN001998/rn_view_BN001998.jpg',
        }],
        Comments: [{
            id: shortId.generate(),
            User: {
                id: shortId.generate(),
                nickname: 'nero',
            },
            content: '우와 개정판이 나왔군요~',
        }, {
            id: shortId.generate(),
            User: {
                id: shortId.generate(),
                nickname: 'hero',
            },
            content: '얼른 사고싶어요~',
            }],
        }],
        imagePaths: [],
        addPostLoading: false,
        addPostDone: false,
        addPostError: null,
        removePostLoading: false,
        removePostDone: false,
        removePostError: null,
        addCommentLoading: false,
        addCommentDone: false,
        addCommentError: null,
    };

initialState.mainPosts = initialState.mainPosts.concat(
    Array(20).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 ADD_POST_REQUEST = 'ADD_POSTS_REQUEST';
    export const ADD_POST_SUCCESS = 'ADD_POSTS_SUCCESS';
    export const ADD_POST_FAILURE = 'ADD_POSTS_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
    });

    export const addComment = (data) => ({
        type: ADD_COMMENT_REQUEST,
        data
    });
    
    const dummyPost = (data) => ({
        id: data.id,
        content: data.content,
        User: {
            id: 1,
            nickname: 'Z0',
        },
        Images: [],
        Comments: [],
    });

    const dummyComment = (data) => ({
        id: shortId.generate(),
        content: data,
        User: {
            id: 1,
            nickname: 'Z1',
        },
    });
    
    // 이전 상태를 액션을 통해 다음 상태로 만들어내는 함수(불변성은 지키면서)
    const reducer = (state = initialState, action) => produce(state, (draft) => {
        switch (action.type) {
            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 = (dummyPost(action.data));
                break;
            case ADD_POST_FAILURE:
                draft.addPostLoading = true;
                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 = state.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;

 

reducers/user.js

import produce from 'immer';

export const initialState = {
    logInLoading: false, // 로그인 시도중
    logInDone: false,
    logInError: null,
    logOutLoading: false, // 로그아웃 시도중
    logOutDone: false,
    logOutError: null,
    signUpLoading: false, // 회원가입 시도중
    signUpDone: false, 
    signUpError: false,
    changeNicknameLoading: false, // 닉네임 변경 시도중
    changeNicknameDone: false, 
    changeNicknameError: false,
    me: null,
    signUpData: {},
    loginData: {}
};

export const LOG_IN_REQUEST = 'LOG_IN_REQUEST';
export const LOG_IN_SUCCESS = 'LOG_IN_SUCCESS';
export const LOG_IN_FAILURE = 'LOG_IN_FAILURE';

export const LOG_OUT_REQUEST = 'LOG_OUT_REQUEST';
export const LOG_OUT_SUCCESS = 'LOG_OUT_SUCCESS';
export const LOG_OUT_FAILURE = 'LOG_OUT_FAILURE';

export const SIGN_UP_REQUEST = 'SIGN_UP_REQUEST';
export const SIGN_UP_SUCCESS = 'SIGN_UP_SUCCESS';
export const SIGN_UP_FAILURE = 'SIGN_UP_FAILURE';

export const CHANGE_NICKNAME_REQUEST = 'CHANGE_NICKNAME_REQUEST';
export const CHANGE_NICKNAME_SUCCESS = 'CHANGE_NICKNAME_SUCCESS';
export const CHANGE_NICKNAME_FAILURE = 'CHANGE_NICKNAME_FAILURE';

export const FOLLOW_REQUEST = 'FOLLOW_REQUEST';
export const FOLLOW_SUCCESS = 'FOLLOW_SUCCESS';
export const FOLLOW_FAILURE = 'FOLLOW_FAILURE';

export const UNFOLLOW_REQUEST = 'UNFOLLOW_REQUEST';
export const UNFOLLOW_SUCCESS = 'UNFOLLOW_SUCCESS';
export const UNFOLLOW_FAILURE = 'UNFOLLOW_FAILURE';

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

const dummyUser = (data) => ({
    ...data,
    nickname: 'zo',
    id: 1,
    Posts: [{id: 1}],
    Followings: [{nickname: 'Boo'}, {nickname: 'B'}, {nickname: 'C'}],
    Followers:  [{nickname: 'ZZ'}, {nickname: 'BB'}, {nickname: 'CC'}]
});

export const loginRequestAction = (data) => {
    return {
        type: LOG_IN_REQUEST,
        data,
    }
}

export const logoutRequestAction = () => {
    return {
        type: LOG_OUT_REQUEST,
    }
}

const reducer = (state = initialState, action) => produce(state, (draft) => {
        switch (action.type) {
            case LOG_IN_REQUEST:
                draft.logInLoading = true;
                draft.logInError = null;
                draft.logInDone = false;
                break;
            case LOG_IN_SUCCESS:
                draft.logInLoading = false;
                draft.me = dummyUser(action.data);
                draft.logInDone = true;
                break;
            case LOG_IN_FAILURE:
                draft.logInLoading = false;
                draft.logInError = action.error;
                break;
            case LOG_OUT_REQUEST:
                draft.logOutLoading = true;
                draft.logOutError = null;
                draft.logOutDone = false;
                break;
            case LOG_OUT_SUCCESS:
                draft.logOutLoading = false;
                draft.logOutDone = true;
                draft.me = null;
                break;  
            case LOG_OUT_FAILURE:
                draft.logOutLoading = false;
                draft.logOutError = action.error;
                break;
            case SIGN_UP_REQUEST:
                draft.signUpLoading = true;
                draft.signUpError = null;
                draft.signUpDone = false;
                break;
            case SIGN_UP_SUCCESS:
                draft.signUpLoading = false;
                draft.signUpDone = true;
                break;
            case SIGN_UP_FAILURE:
                draft.signUpLoading = false;
                draft.signUpError = action.error;
                break;
            case CHANGE_NICKNAME_REQUEST:
                draft.changeNicknameLoading = true;
                draft.changeNicknameError = null;
                draft.changeNicknameDone = false;
                break;
            case CHANGE_NICKNAME_SUCCESS:
                draft.changeNicknameLoading = false;
                draft.changeNicknameDone = true;
                break;
            case CHANGE_NICKNAME_FAILURE:
                draft.changeNicknameLoading = false;
                draft.changeNicknameError = action.error;
                break;
            // 게시글 등록
            case ADD_POST_TO_ME:
                draft.me.Posts.unshift({id: action.data});
                break;

                // return {
                //     ...state,
                //     me: {
                //         ...state.me,
                //         Posts: [{ id: action.data }, ..state.me.Posts],
                //     },
                // };

            // 게시글 삭제
            case REMOVE_POST_OF_ME:
                draft.me.Posts = draft.me.Posts.filter((v) => v.id !== action.data);
                break;

                // return {
                //     ...state,
                //     me: {
                //         ...state.me,
                //         Posts: state.me.Posts.filter((v) => v.id !== action.data)
                //     },
                // };

            default:
                break;
        } 
    });

export default reducer;

 

pages/profile.js

import Head from 'next/head';
import React, {useEffect} from 'react';
import Router from 'next/router';
import AppLayout from '../components/AppLayout';
import NicknameEditForm from '../components/NicknameEditFrom';
import FollowList from '../components/FollowList';
import { useSelector } from 'react-redux';

const Profile = () => {
    const {me} = useSelector((state) => state.user);

    useEffect(() => {
        if (!(me && me.id)) {
            Router.push('/');
        }
    }, [me && me.id]);

    if(!me) {
        return null;
    }

    return (
        <AppLayout>
            <Head>
                <title>내 프로필 | NodeBird</title>
            </Head>
            <NicknameEditForm />
            <FollowList header="팔로잉" data={me.Followings} />
            <FollowList header="팔로워" data={me.Followers} />
            </AppLayout>
    ) 
}

export default Profile;  

로그인하고 게시글 쓰면 profile.js에 useEffect쪽 '/' 루트로 가지는거 같습니다

빈 창 떠요

답변 1

0

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

  1. postData가 undefined인 것부터 해결해야할 것 같습니다. PostCardContent를 사용하는 컴포넌트에서 postData가 제대로 전달되고 있나 봐야합니다. 리덕스에서부터 보는게 좋습니다. 그리고 첫 스크린샷에서 에러가 3개 있기 때문에 세 가지 에러를 다 알려주세요.

  2. 댓글 달면 어떻게 되는 건지 구체적으로 알려주세요.

br님의 프로필 이미지
br
질문자

image

image

image

image여기 댓글 달면

image

이렇게 빈창 이에요

아래 댓글에러인듯합니다

image

image

어제 댓글오류 찾아서 분명 잘 되는거까지 확인하고 강의 이어서 들었는데

faker 설치하고 immer 설치하고 또 이러네여 다시 reducers부터 찾아보겠습니다 ㅠㅠ

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

이 부분은 mainPosts가 배열이 아니게 된 겁니다. 중간에 리덕스 액션중에 mainPosts를 배열이 아니게 만들어버린 액션이 있을 겁니다. 리덕스 데브툴로 하나씩 봐서 찾아내보세요!

br님의 프로필 이미지
br
질문자

네 찾아보겠습니다ㅠ

혹시 faker는 5버전으로 받으면 되는거죠?? 찾아보니까 불안정하다고 본듯해서요

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

faker@5버전으로 받으시거나 6버전은

npm install @faker-js/faker

이걸로 받으셔야 합니다. import할 때도 저 패키지를 임포트해야합니다.

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

5버전은 괜찮습니다. 불안정한게 아니라 관리자가 미쳐버려서 6버전을 망치고 도망간 겁니다.

br님의 프로필 이미지
br

작성한 질문수

질문하기