강의

멘토링

커뮤니티

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

hib4888님의 프로필 이미지
hib4888

작성한 질문수

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

faker로 실감나는 더미데이터 만들기

faker사용시 이미지가 동일하게 출력되는데 오류가 있는걸까요?

해결된 질문

작성

·

339

0

안녕하세요 제로초님 강의 잘 듣고있습니다.

faker를 사용해서 더미데이터를 출력해봤는데

제로초님과는 다르게 이미지가 같은 이미지로 출력되더라고요

제가 코드를 잘못작성해서인건지, 아니면 faker라이브러리의 문제인건지 혹시 이유를 알 수 있을까요?

// pages/index.js

import React, { useCallback, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Button } from 'antd';
import { PlusCircleOutlined } from '@ant-design/icons';
import Link from 'next/link';

import { 
  HomeWrapper, HomeLogoHeader, HomeLogoText, PageMainText, PageSubText, HomeInputWrapper
} from '../pagestyles';
import { LOAD_POSTS_REQUEST } from '../reducers/post';
import AppLayout from '../components/AppLayout';
import PostList from '../components/HomePost/PostList';

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

  const onSearch = useCallback((value) => {
    console.log(value);
  }, []);

  useEffect(() => {
    dispatch({
      type: LOAD_POSTS_REQUEST
    });    
  }, []);

  
  useEffect(() => {
    function onScroll() {
      console.log(window.scrollY, document.documentElement.clientHeight, document.documentElement.scrollHeight);
      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>
      <HomeWrapper>
        <HomeLogoHeader>
          <HomeLogoText>
            <PageMainText>Recipe.io</PageMainText>
            <PageSubText>Have a delicious meal today</PageSubText>
          </HomeLogoText>
          {me && <Link href='/posting'><a><Button type='primary' size='large' icon={<PlusCircleOutlined />} >Create Recipe</Button></a></Link>}
        </HomeLogoHeader>
        
        <HomeInputWrapper 
          placeholder="Search for Recipe" 
          size='large' 
          allowClear="true" 
          enterButton 
          onSearch={onSearch}
        />
        
        <PostList mainPosts={mainPosts} />
      </HomeWrapper>
    </AppLayout>
  )
};

export default Home;

 

// reducers/post.js

import produce from 'immer';
import shortId from 'shortid';
import { faker } from '@faker-js/faker';

export const initialState = {
  mainPosts: [],
  imagePaths: [],
  hasMorePosts: true,
  loadPostsLoading: false,
  loadPostsDone: false,
  loadPostsError: null,
  addPostLoading: false,
  addPostDone: false,
  addPostError: null,
  removePostLoading: false,
  removePostDone: false,
  removePostError: null,
  addCommentLoading: false,
  addCommentDone: false,
  addCommentError: null,
  removeCommentLoading: false,
  removeCommentDone: false,
  removeCommentError: null,
};

export const generateDummyPost = (num) => Array(num).fill().map(() => ({  
  id: shortId.generate(),
  User: {
    id: shortId.generate(),
    nickname: faker.name.findName(),
  },
  title: faker.lorem.slug(),
  desc: faker.lorem.sentence(),    
  content: [{
    ingredient: faker.lorem.paragraphs(),
  }, {
    recipes: faker.lorem.paragraphs(),
  }, {
    tips: faker.lorem.paragraphs(),
  }],
  Images: [{
    id: shortId.generate(),
    src: faker.image.food(),      
  }, {
    id: shortId.generate(),
    src: faker.image.food(),
  }, {
    id: shortId.generate(),
    src: faker.image.food(),
  }],
  tag: '맛있을것같아요 #hashtag1 짱짱맨!! #hashtag2 ##hashtag3',      
  Comments: [{
    id: shortId.generate(),
    User: {
      id: shortId.generate(),
      nickname: faker.name.findName(),
    },
    content: faker.lorem.sentence(),
  }, {
    id: shortId.generate(),
    User: {
      id: shortId.generate(),
      nickname: faker.name.findName(),
    },
    content: faker.lorem.sentence(),
  }]  
}));

export const dummyPost = (data) => ({
  id: data.id,
  User: {
    id: 2,
    nickname: 'Mirrer',
  },
  title: data.content.title,
  desc: data.content.desc,   
  content: [{
    ingredient: data.content.ingredient,
  }, {
    recipes: data.content.recipes,
  }, {
    tips: data.content.tips,
  }],
  tag: data.content.tags,      
  Images: [{
    id: shortId.generate(),
    src: faker.image.food(),
  }, {
    id: shortId.generate(),
    src: faker.image.food(),
  }],
  Comments: [{
    id: shortId.generate(),
    User: {
      id: shortId.generate(),
      nickname: faker.name.findName(),
    },
    content: faker.lorem.sentence(),
  }],
});

const dummyComment = (data) => ({
  id: data.id,
  User: {
    id: 2,
    nickname: 'Mirrer',
  },
  content: data.commentText,
});

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 REMOVE_COMMENT_REQUEST = 'REMOVE_COMMENT_REQUEST';
export const REMOVE_COMMENT_SUCCESS = 'REMOVE_COMMENT_SUCCESS';
export const REMOVE_COMMENT_FAILURE = 'REMOVE_COMMENT_FAILURE';

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

export const removePostRequestAction = (data) => {  
  return {
    type: REMOVE_POST_REQUEST,
    data,
  }
};

export const addCommentRequestAction = (data) => {    
  return {
    type: ADD_COMMENT_REQUEST,
    data,
  } 
};

export const removeCommentRequestAction = (data) => {  
  return {
    type: REMOVE_COMMENT_REQUEST,
    data,
  }
};

const reducer = (state = initialState, action) => {
  return 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 < 30;
        break;
      case LOAD_POSTS_FAILURE:
        draft.loadPostsLoading = false;
        draft.loadPostsError = 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.mainPosts = draft.mainPosts.filter((v) => v.id !== action.data);
        draft.removePostLoading = false;
        draft.removePostDone = true;
        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));
        draft.addCommentLoading = false;
        draft.addCommentDone = true;      
        break;  
      }
      case ADD_COMMENT_FAILURE:
        draft.addCommentLoading = false;
        draft.addCommentError = action.error;
        break;      
      case REMOVE_COMMENT_REQUEST:
        draft.removeCommentLoading = true;
        draft.removeCommentDone = false;
        draft.removeCommentError = null;
        break;
      case REMOVE_COMMENT_SUCCESS: {        
        // action.data = { postId: 1, commentId: '댓글id'}
        const post = draft.mainPosts.find((v) => v.id === action.data.postId);        
        draft.removeCommentLoading = false;
        draft.removeCommentDone = true;
        break;
      }
      case REMOVE_COMMENT_FAILURE:
        draft.removeCommentLoading = false;
        draft.removeCommentError = action.error;
        break;
      default:
        break;
    }
  });
};

export default reducer;

 

// sagas/post.js

import { all, fork, delay, put, takeLatest } from 'redux-saga/effects';
import shortId from 'shortid';
// import axios from 'axios';
import {
  LOAD_POSTS_REQUEST, LOAD_POSTS_SUCCESS, LOAD_POSTS_FAILURE, generateDummyPost,
  ADD_POST_REQUEST, ADD_POST_SUCCESS, ADD_POST_FAILURE, 
  REMOVE_POST_REQUEST, REMOVE_POST_SUCCESS, REMOVE_POST_FAILURE,
  ADD_COMMENT_REQUEST, ADD_COMMENT_SUCCESS, ADD_COMMENT_FAILURE,
  REMOVE_COMMENT_REQUEST, REMOVE_COMMENT_SUCCESS, REMOVE_COMMENT_FAILURE, 
} from '../reducers/post';
import { BOARD_ADD_POST_TO_ME, BOARD_REMOVE_POST_OF_ME } from '../reducers/user';

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

function* loadPosts(action) {   
  try {
    // const result = yield call(addPostAPI, 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 addPostAPI(data) {
//   return axios.post('/api/post', data);
// }

function* addPost(action) {   
  try {
    // const result = yield call(addPostAPI, action.data);
    const id = shortId.generate();
    yield delay(1000);    
    yield put({
      type: ADD_POST_SUCCESS,
      data: {
        id,
        content: action.data,
      }
    })
    yield put({
      type: BOARD_ADD_POST_TO_ME,
      data: {
        id,
        content: action.data,
      }
    })
  } catch(err) {
    yield put({ 
      type: ADD_POST_FAILURE,
      data: err.response.data 
    })
  }  
}

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

function* removePost(action) {   
  try {
    // const result = yield call(addPostAPI, action.data);    
    yield delay(1000);    
    yield put({
      type: REMOVE_POST_SUCCESS,
      data: action.data,
    })
    yield put({
      type: BOARD_REMOVE_POST_OF_ME,
      data: action.data,
    })
  } catch(err) {
    yield put({ 
      type: REMOVE_POST_FAILURE,
      data: err.response.data 
    })
  }  
}

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

function* addComment(action) { 
  const id = shortId.generate();  
  try {
    // const result = yield call(addCommentAPI, action.data);        
    yield delay(1000);
    yield put({
      type: ADD_COMMENT_SUCCESS,
      data: {
        id,
        postId: action.data.postId,
        commentText: action.data.commentText,
      }
    })
  } catch(err) {
    yield put({ 
      type: ADD_COMMENT_FAILURE,
      data: err.response.data 
    })
  }  
}

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

function* removeComment(action) {   
  try {
    // const result = yield call(addPostAPI, action.data);    
    yield delay(1000);    
    yield put({
      type: REMOVE_COMMENT_SUCCESS,
      data: {
        postId: action.data.postId,
        commentId: action.data.commentId,
      },
    })
  } catch(err) {
    yield put({ 
      type: REMOVE_COMMENT_FAILURE,
      data: err.response.data 
    })
  }  
}

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

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* watchRemoveComment() {    
  yield takeLatest(REMOVE_COMMENT_REQUEST, removeComment);  
}

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

답변 1

0

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

원래 같은 게 나오는 게 맞을겁니다.

food(640, 480, true) 이런 식으로 하면 랜덤하게 나옵니다.

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

빠른 답변 감사합니다!!

hib4888님의 프로필 이미지
hib4888

작성한 질문수

질문하기