묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결화이트해커가 되기 위한 8가지 웹 해킹 기술
이부분에서 왜 에러가 생기는 건가요?
(사진)
-
미해결[라즈베리파이] IoT 딥러닝 Computer Vision 실전 프로젝트
LiDAR 센서에 관하여 질문드립니다.
강의를 들으면서 라즈베리파이를 공부하면서 따로 LiDAR센서를 사용하려고 합니다. 혹시 LiDAR에 관한 강의나 질문같은걸 드려도 되나요? 수업내용엔 없는 내용이라 먼저 여쭈어 봅니다.
-
미해결아마존 클라우드 무료계정으로 시작하는 서버리스 애플리케이션 프로젝트
API Key를 request.heade에 넣으면...
HP님 안녕하세요. API Key를 사용하는 목적 자체가 안전성?보안?을 위해서인데, 강의처럼 api.js에 첨부하면, client에게 키가 그대로 공개되지 않나요?
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 기본 강의
postman 오류 질문
안녕하세요 ! 수업 잘 듣고 있습니다 postman 에서 send 하면 오류가 나는데 어디가 잘못된 걸까요? index.js 소스 첨부합니다 ! const express = require('express') const app = express() const port = 5000 const bodyParser = require('body-parser'); const { User } = require("./models/User"); app.use(bodyParser.urlencoded({extended:true})); app.use(bodyParser.json()); const mongoose = require('mongoose') mongoose.connect('mongodb+srv://root:1234@boilerplate.ielul.mongodb.net/<dbname>?retryWrites=true&w=majority',{ useNewUrlParser:true,useUnifiedTopology:true,useCreateIndex:true,useFindAndModify:false }).then(()=>console.log('MongoDB Connected...')) .catch(err=>console.log(err)) app.get('/', (req, res) => { res.send('Hello World!') }) app.post('/register',(req,res)=>{ //회원 가입시 필요한 정보를 클라이언트에서 가져오면 //데이터베이스에 넣는다 const user = new User(req.body) user.save((err,userInfo)=>{ if(err) return res.json({success:false,err}) return res.status(200).json({ success:true }) }) }) app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) })
-
해결됨[리뉴얼] 파이썬입문과 크롤링기초 부트캠프 [파이썬, 웹, 데이터 이해 기본까지] (업데이트)
exercise 문제 file은 어디에 있습니까?
안녕하십니까? exercise file이 제공된 곳을 알려주십시요.
-
해결됨정말 쉽게 풀어보는 코딩 테스트 top 기본 문제 (with 자바)
PriorityQueue 오류 수정 부분
안녕하세요 강의를 잘 듣다가 궁굼한 점이 생겨서 질문 드립니다. PriorityQueue(intervals, Comp2) → PriorityQueue(intervals.length, Comp2) 로 수정하는 부분에서 왜 length를 붙여줘야 오류가 없어지는지 궁금합니다. +) Queue<Interval> heap = new PriorityQueue<Interval>() 로 해서 우선순위큐에 저장하면 밑에 for문에서 인자를 넣고 빼는 과정을 수행해도 우선순위에 의해서 정렬이 자동으로 되는건가요?
-
미해결해커를 위한 iOS 앱 모의 해킹 전문 과정
keychain_dump 오류
강의를 따라서 keychain_dumper 를 설치 후, 동작을 하니 다음과 같은 오류가 발생합니다. 혹시 해결하는 방법이 있을까요?
-
해결됨애플 웹사이트 인터랙션 클론!
오류가 나는데 뭐가 문제인지 모르겠어요ㅠㅠ
(() => { let yOffset = 0; // window.pageYOffset 대신 쓸 변수 let prevScrollHeight = 0; // 현재 스크롤 위치(yOffset)보다 이전에 위치한 스크롤 섹션들의 스크롤 높이값의 합 let currentScene = 0; // 현재 활성화된(눈 앞에 보고있는) 씬(scroll-section) const sceneInfo = [ { // 0 type: 'sticky', heightNum: 5, //브라우저 높이의 5배로 scrollHeight 세팅 scrollHeight: 0, objs: { container: document.querySelector('#scroll-section-0') } }, { // 1 type: 'normal', heightNum: 5, //브라우저 높이의 5배로 scrollHeight 세팅 scrollHeight: 0, objs: { container: document.querySelector('#scroll-section-1') } }, { // 2 type: 'sticky', heightNum: 5, //브라우저 높이의 5배로 scrollHeight 세팅 scrollHeight: 0, objs: { container: document.querySelector('#scroll-section-2') } }, { // 3 type: 'sticky', heightNum: 5, //브라우저 높이의 5배로 scrollHeight 세팅 scrollHeight: 0, objs: { container: document.querySelector('#scroll-section-3') } } ]; function setLayout() { // 각 스크롤 섹션의 높이 세팅 for (let i = 0; i < sceneInfo.length; i++){ sceneInfo[i].scrollHeight = sceneInfo[i].heightNum * window.innerHeight; sceneInfo[i].objs.container.style.height = `${sceneInfo[i].scrollHeight}px`; } //console.log(sceneInfo); } function scrollLoop() { for (let i = 0; i < currentScene; i++) { prevScrollHeight += sceneInfo[i].scrollHeight; } //console.log(prevScrollHeight); if (yOffset > prevScrollHeight + sceneInfo[currentScene].scrollHeight) { currentScene++; } if (yOffset < prevScrollHeight) { currentScene--; } console.log(currentScene); } window.addEventListener('resize', setLayout); window.addEventListener('scroll', () => { yOffset = window.pageYOffset; scrollLoop(); }); setLayout(); })();
-
미해결[개정판] 파이썬 머신러닝 완벽 가이드
full_matrices인자의 의미
안녕하세요! 질문하나만 드리겠습니다! scipy의 svd 함수에서 full_matrices 인자가 True/ False에 따라 SVD분할할 때 분할한 행렬들의 차원수가 달라지는 것 같은데.. T/F값에 따라 궁극적으로 미치는 영향이 무엇인가요..? 이것도 일종의 Compact SVD인건가요..? 저 U, Sigma, Vt의 각 shape를 반환해보면 모두 (6,6) , (6,), (6,6)으로 반환되는거 보면 차원 축소는 아닌 것 같은데...밑의 주석으로 쓴 것은 documentation을 보고 해석해놓은 건데.. 정확히 저게 어떤 영향을 미치는지 궁금합니다..!
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
질문있습니다.
우선적으로 좋은 강의 주셔서 감사하다는 말씀 먼저 드리고싶구요 ㅎ 이전에는 next 를 사용하지 않고 react 를 사용하는 강의라던지 블로그라던지 등등을 봤었는데요 . 지금은 제로초 님 강의에서 next 를 들으면서 드는생각이 코드적인 부분에서 크게 차이가 없는데 , 물론 앞서 설명하신 부분에 대해서 이해는 했지만 코드적인 부분에서 무엇이 다른지 잘 이해가 안갑니다. import React from "react"; 를 적지 않는거,..? 라고 우선 기억을 하고있는데요 .무슨 차이가 있을까요
-
미해결C 프로그래밍 - 입문부터 게임 개발까지
256이 궁금합니다.
/*char str[256]; scanf_s("%s", str, sizeof(str)); printf("%s\n", str);*/ 이부분에서 왜 하필 크기를 정해줄 때 256이라는 숫자를 사용하는거에요?? 그냥 아무 숫자나 큰 걸로 고르신건가요??
-
해결됨MQTT 사물인터넷 통신 프로젝트 (Arduino, MQTT, Node.js, mongoDB, Android)
mqtt전송
안녕하세요! 좋은 강의를 만나 프로젝트를 무난하게 진행하고 있던 와중 궁금한 점이 생겨 이렇게 질문드립니다. 혹시 publisher가 서버에 json데이터만이 아닌 이미지파일을 전송하려고 하는것도 가능할까요??!
-
미해결리버스쿨 Level3 - 안드로이드 모바일 리버싱
녹스를 제공받은 vmware 리눅스 os에서 실행을 시키는건가요 아니면 기존에 사용중인 윈도우에서 실행을 시키는건가요>??
윈도우에서 녹스를 실행시켰을 때 ip가 172로 잡히고 리눅스 ip는 192여서 adb connect 를 했을 때 연결이 안되는것 같아요.. 녹스를 리눅스로 파일을 옮기고 해봤는데도 exe라서 실행이 안되는것 같고 해결방안을 좀 알 수 있을가요.. 4일동안 구글링을 해봤는데도 안나와서 질문드려요 ㅠㅠ
-
미해결유니티(Unity)로 시작하는 게임개발: Part 2. C# 프로그래밍 입문
유니티 프로그램 다운로드 후 프로젝트 실행할 때
프로젝트에서 새로 생성을 클릭 후 생선버튼을 눌렀을 때 "에디터 실행 중 오류가 발생했습니다. 라이선스가 유효하지 않습니다" 라고 합니다. 어떻게 해야 되나요?
-
미해결쉽게 배우는 Webpack
리뉴얼 강의 쿠폰 발급 부탁드립니다.
늦게 봐서 확인을 못헀습니다 ㅜㅜ 부탁드려도 될까요?
-
JSP 웹 쇼핑몰 프로그래밍 기본 과정(JSP WEB Programming)
mvc2 도 그렇고 이 강의도 유튜브에 업로드 되어 있는 것 같은데요..
삭제된 글입니다
-
미해결[개정판] 딥러닝 컴퓨터 비전 완벽 가이드
GPU와 TPU차이
최근에 코랩에 TPU도 추가가 된거 같은데 GPU를 썻을때와 TPU를 썻을때에 성능차이가 있을까요?
-
미해결애플 웹사이트 인터랙션 클론!
강의등록만해놓고진도가안나가네요(@^^@)
열심히 해야하는데... 업무핑계로 계속 미루고있네요 ㅠㅠ 강의는 초반만 조금 봤는데... 디테일하게 알려주셔서 너무 좋더라구요... 다음강의도 좀더 좋은 컨텐츠로 부탁드립니다.
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
안녕하세요. useEffect 관련 질문 드립니다!
안녕하세요 useEffect hooks 관련해서 질문드립니다.useEffect를 하지 않았을경우 당연히 렌더는 1번되지만 useEffect로 디스패치를 하면 렌더링이 3번됩니다. 이게 정상인지 아닌지 잘 모르겠어서 질문드립니다..
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
user/[id].js => Unhandled Runtime Error TypeError: Cannot read property 'id' of undefined 에러가 발생합니다.
페이지 로딩은 정상적으로 되는데 스크롤시 에러가 발생합니다. <Head> 태그 url 부분을 약간 다르게 수정해 주었고 다른 부분은 이상이 없어 보입니다. 로그를 찍어 봤는데.. 값이 나오는데 값을 찾을수 없다...???? user/[id].js const User = () => { const dispatch = useDispatch(); const router = useRouter(); const { id } = router.query; <==== 이부분에서 id 값은 잘 받아 오는것 같습니다. console.log(router.query); <==== 로그를 찍어보니 {id: "1"} 로 나옵니다. github에 올리신 파일로 돌려서 로그를 찍어 본 결과 값도 동일하게 string 인데.. 정상적으로 스크롤 됩니다. const { mainPosts, hasMorePosts, loadPostsLoading } = useSelector((state) => state.post); const { userInfo } = useSelector((state) => state.user); FRONT user/[id]/.js // user/[id].js import React, { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { Avatar, Card } from 'antd'; import { END } from 'redux-saga'; import Head from 'next/head'; import { useRouter } from 'next/router'; import axios from 'axios'; import { LOAD_USER_POSTS_REQUEST } from '../../reducers/post'; import { LOAD_MY_INFO_REQUEST, LOAD_USER_REQUEST } from '../../reducers/user'; import PostCard from '../../components/PostCard'; import wrapper from '../../store/configureStore'; import AppLayout from '../../components/AppLayout'; import { backUrl } from '../../config/config'; // 프론트서버와 브라우저 모두에서 실행 const User = () => { const dispatch = useDispatch(); const router = useRouter(); const { id } = router.query; <==== 이부분에서 id 값은 잘 받아 오는것 같습니다. console.log(router.query); <==== 로그를 찍어보니 {id: "1"} 로 나옵니다. github에 올리신 파일로 돌려서 로그를 찍어 본 결과도 동일한데.. 정상적으로 스크롤 됩니다. const { mainPosts, hasMorePosts, loadPostsLoading } = useSelector((state) => state.post); const { userInfo } = useSelector((state) => state.user); useEffect(() => { function onScroll() { if (window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight - 300) { if (hasMorePosts && !loadPostsLoading) { dispatch({ type: LOAD_USER_POSTS_REQUEST, lastId: mainPosts[mainPosts.length - 1] && mainPosts[mainPosts.lenth - 1].id, <====== 에러가 발생하는 부분 data: id, }); } } } window.addEventListener('scroll', onScroll); return () => { window.removeEventListener('scroll', onScroll); }; }, [ mainPosts.length, hasMorePosts, id]); return ( <AppLayout> <Head> <title> {userInfo.nickname} 님의 글 </title> <meta name="description" content={`${userInfo.nickname}님의 게시글`} /> <meta property="og:title" content={`${userInfo.nickname}님의 게시글`} /> <meta property="og:description" content={`${userInfo.nickname}님의 게시글`} /> <meta property="og:image" content={`${backUrl}/favicon.ico`} /> <meta property="og:url" content={`${backUrl}/user/${id}`} /> </Head> {userInfo ? ( <Card actions={[ <div key="twit"> 짹짹 <br /> {userInfo.Posts} </div>, <div key="following"> 팔로잉 <br /> {userInfo.Followings} </div>, <div key="follower"> 팔로워 <br /> {userInfo.Followers} </div>, ]} > <Card.Meta avatar={<Avatar>{userInfo.nickname[0]}</Avatar>} title={userInfo.nickname} /> </Card> ) : null} {mainPosts.map((c) => ( <PostCard key={c.id} post={c} /> ))} </AppLayout> ); }; // front server 에서 실행 export const getServerSideProps = wrapper.getServerSideProps(async (context) => { const cookie = context.req ? context.req.headers.cookie : ''; axios.defaults.headers.Cookie = ''; if (context.req && cookie) { axios.defaults.headers.Cookie = cookie; } context.store.dispatch({ type: LOAD_USER_POSTS_REQUEST, data: context.params.id, }); context.store.dispatch({ type: LOAD_MY_INFO_REQUEST, }); context.store.dispatch({ type: LOAD_USER_REQUEST, data: context.params.id, }); context.store.dispatch(END); await context.store.sagaTask.toPromise(); // return { props: {} }; }); export default User; config/config.js const domainUrl = 'https://api.nodebird.com'; const localhostUrl = 'http://localhost:3065'; const backUrl = process.env.NODE_ENV === 'production' ? 'https://api.nodebird.com' : 'http://localhost:3065'; export { backUrl, domainUrl, localhostUrl }; BACK sagas/user.js // all fork call put delay debounce throttle takeLatest tabkeEvery takeLeding taekMaybe import { all, fork, put, takeLatest, throttle, call } from 'redux-saga/effects'; import axios from 'axios'; // import shortId from 'shortid'; import { LOAD_POSTS_REQUEST, LOAD_POSTS_SUCCESS, LOAD_POSTS_FAILURE, LOAD_USER_POSTS_REQUEST, LOAD_USER_POSTS_SUCCESS, LOAD_USER_POSTS_FAILURE, LOAD_HASHTAG_POSTS_REQUEST, LOAD_HASHTAG_POSTS_SUCCESS, LOAD_HASHTAG_POSTS_FAILURE, LOAD_POST_REQUEST, LOAD_POST_SUCCESS, LOAD_POST_FAILURE, LIKE_POST_REQUEST, LIKE_POST_SUCCESS, LIKE_POST_FAILURE, UNLIKE_POST_REQUEST, UNLIKE_POST_SUCCESS, UNLIKE_POST_FAILURE, ADD_POST_REQUEST, ADD_POST_SUCCESS, ADD_POST_FAILURE, ADD_COMMENT_REQUEST, ADD_COMMENT_SUCCESS, ADD_COMMENT_FAILURE, REMOVE_POST_REQUEST, REMOVE_POST_SUCCESS, REMOVE_POST_FAILURE, UPLOAD_IMAGES_REQUEST, UPLOAD_IMAGES_SUCCESS, UPLOAD_IMAGES_FAILURE, RETWEET_REQUEST, RETWEET_SUCCESS, RETWEET_FAILURE, } from '../reducers/post'; import { ADD_POST_TO_ME, REMOVE_POST_OF_ME, } from '../reducers/user'; function likePostAPI(data) { return axios.patch(`/post/${data}/like`); }; function* likePost(action) { try { const result = yield call(likePostAPI, action.data); yield put({ type: LIKE_POST_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: LIKE_POST_FAILURE, error: err.response.data, }); } } function unlikePostAPI(data) { return axios.delete(`/post/${data}/like`); }; function* unlikePost(action) { try { const result = yield call(unlikePostAPI, action.data); yield put({ type: UNLIKE_POST_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: UNLIKE_POST_FAILURE, error: err.response.data, }); } } function loadPostsAPI(lastId) { return axios.get(`/posts?lastId=${lastId || 0}`); }; function* loadPosts(action) { try { const result = yield call(loadPostsAPI, action.lastId); yield put({ type: LOAD_POSTS_SUCCESS, data: result.data, // data: generateDummyPost(10), }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: LOAD_POSTS_FAILURE, error: err.response.data, }); } } function loadPostAPI(data) { return axios.get(`/post/${data}`); }; function* loadPost(action) { try { const result = yield call(loadPostAPI, action.data); yield put({ type: LOAD_POST_SUCCESS, data: result.data, // data: generateDummyPost(10), }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: LOAD_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 delay(1000); yield put({ type: ADD_COMMENT_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: ADD_COMMENT_FAILURE, error: err.response.data, }); }; }; function addPostAPI(data) { return axios.post('/post', data); }; function* addPost(action) { try { const result = yield call(addPostAPI, action.data); yield put({ type: ADD_POST_SUCCESS, data: result.data }); yield put({ type: ADD_POST_TO_ME, data: result.data.id, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: ADD_POST_FAILURE, error: err.response.data, }); }; }; function removePostAPI(data) { return axios.delete(`/post/${data}`); }; function* removePost(action) { try { const result = yield call(removePostAPI, action.data); yield put({ type: REMOVE_POST_SUCCESS, data: result.data, }); console.log('removePost'); yield put({ type: REMOVE_POST_OF_ME, data: action.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: REMOVE_POST_FAILURE, error: err.response.data, }); }; }; function uploadImagesAPI(data) { return axios.post('/post/images', data); // POST /post/images }; function* uploadImages(action) { try { const result = yield call(uploadImagesAPI, action.data); yield put({ type: UPLOAD_IMAGES_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: UPLOAD_IMAGES_FAILURE, error: err.response.data, }); }; }; function retweetAPI(data) { return axios.post(`/post/${data}/retweet`); // POST /post/images }; function* retweet(action) { try { const result = yield call(retweetAPI, action.data); yield put({ type: RETWEET_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: RETWEET_FAILURE, error: err.response.data, }); }; }; function loadHashtagPostsAPI(data, lastId) { return axios.get(`/hashtag/${data}?lastId=${lastId || 0}`); }; function* loadHashtagPosts(action) { try { const result = yield call(loadHashtagPostsAPI, action.data, action.lastId); yield put({ type: LOAD_HASHTAG_POSTS_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ type: LOAD_HASHTAG_POSTS_FAILURE, error: err.response.data, }); } } function loadUserPostsAPI(data, lastId) { return axios.get(`/user/${data}/posts?lastId=${lastId || 0}`); }; function* loadUserPosts(action) { try { const result = yield call(loadUserPostsAPI, action.data, action.lastId); yield put({ type: LOAD_USER_POSTS_SUCCESS, data: result.data, // data: generateDummyPost(10), }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: LOAD_USER_POSTS_FAILURE, error: err.response.data, }); } } function* watchLoadUserPosts() { yield throttle(5000, LOAD_USER_POSTS_REQUEST, loadUserPosts); }; function* watchLoadHashtagPosts() { // 5초에 한번 게사글이 로드 된다. yield throttle(5000, LOAD_HASHTAG_POSTS_REQUEST, loadHashtagPosts); }; function* watchLoadPosts() { // 5초에 한번 게사글이 로드 된다. yield throttle(5000, LOAD_POSTS_REQUEST, loadPosts); }; function* watchLoadPost() { // 5초에 한번 게사글이 로드 된다. yield takeLatest(LOAD_POST_REQUEST, loadPost); }; function* watchRetweet() { // 5초에 한번 게사글이 로드 된다. yield takeLatest(RETWEET_REQUEST, retweet); }; function* watchAddPost() { yield takeLatest(ADD_POST_REQUEST, addPost); }; function* watchUploadImages() { yield takeLatest(UPLOAD_IMAGES_REQUEST, uploadImages); }; function* watchAddComment() { yield takeLatest(ADD_COMMENT_REQUEST, addComment); }; function* watchRemovePost() { yield takeLatest(REMOVE_POST_REQUEST, removePost); }; function* watchLikePost() { yield takeLatest(LIKE_POST_REQUEST, likePost); }; function* watchUnLikePost() { yield takeLatest(UNLIKE_POST_REQUEST, unlikePost); }; export default function* postSaga() { yield all([ fork(watchRetweet), fork(watchUploadImages), fork(watchLikePost), fork(watchUnLikePost), fork(watchAddPost), fork(watchLoadPosts), fork(watchLoadHashtagPosts), fork(watchLoadUserPosts), fork(watchLoadPost), fork(watchRemovePost), fork(watchAddComment), ]); }; reducers/post.js reducers/user.js FRONT user/[id]/.js import React, { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { Avatar, Card } from 'antd'; import { END } from 'redux-saga'; import Head from 'next/head'; import { useRouter } from 'next/router'; import axios from 'axios'; import { LOAD_USER_POSTS_REQUEST } from '../../reducers/post'; import { LOAD_MY_INFO_REQUEST, LOAD_USER_REQUEST } from '../../reducers/user'; import PostCard from '../../components/PostCard'; import wrapper from '../../store/configureStore'; import AppLayout from '../../components/AppLayout'; import { backUrl } from '../../config/config'; // 프론트서버와 브라우저 모두에서 실행 const User = () => { const dispatch = useDispatch(); const router = useRouter(); const { id } = router.query; <==== 이부분에서 id 값은 잘 받아 오는것 같습니다. console.log(router.query); <==== 로그를 찍어보니 {id: "1"} 로 나옵니다. github에 올리신 파일로 돌려서 로그를 찍어 본 결과도 동일한데.. 정상적으로 스크롤 됩니다. const { mainPosts, hasMorePosts, loadPostsLoading } = useSelector((state) => state.post); const { userInfo } = useSelector((state) => state.user); useEffect(() => { function onScroll() { if (window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight - 300) { if (hasMorePosts && !loadPostsLoading) { dispatch({ type: LOAD_USER_POSTS_REQUEST, lastId: mainPosts[mainPosts.length - 1] && mainPosts[mainPosts.lenth - 1].id, <====== 에러가 발생하는 부분 data: id, }); } } } window.addEventListener('scroll', onScroll); return () => { window.removeEventListener('scroll', onScroll); }; }, [ mainPosts.length, hasMorePosts, id]); return ( <AppLayout> <Head> <title> {userInfo.nickname} 님의 글 </title> <meta name="description" content={`${userInfo.nickname}님의 게시글`} /> <meta property="og:title" content={`${userInfo.nickname}님의 게시글`} /> <meta property="og:description" content={`${userInfo.nickname}님의 게시글`} /> <meta property="og:image" content={`${backUrl}/favicon.ico`} /> <meta property="og:url" content={`${backUrl}/user/${id}`} /> </Head> {userInfo ? ( <Card actions={[ <div key="twit"> 짹짹 <br /> {userInfo.Posts} </div>, <div key="following"> 팔로잉 <br /> {userInfo.Followings} </div>, <div key="follower"> 팔로워 <br /> {userInfo.Followers} </div>, ]} > <Card.Meta avatar={<Avatar>{userInfo.nickname[0]}</Avatar>} title={userInfo.nickname} /> </Card> ) : null} {mainPosts.map((c) => ( <PostCard key={c.id} post={c} /> ))} </AppLayout> ); }; // front server 에서 실행 export const getServerSideProps = wrapper.getServerSideProps(async (context) => { const cookie = context.req ? context.req.headers.cookie : ''; axios.defaults.headers.Cookie = ''; if (context.req && cookie) { axios.defaults.headers.Cookie = cookie; } context.store.dispatch({ type: LOAD_USER_POSTS_REQUEST, data: context.params.id, }); context.store.dispatch({ type: LOAD_MY_INFO_REQUEST, }); context.store.dispatch({ type: LOAD_USER_REQUEST, data: context.params.id, }); context.store.dispatch(END); await context.store.sagaTask.toPromise(); // return { props: {} }; }); export default User; config/config.js const domainUrl = 'https://api.nodebird.com'; const localhostUrl = 'http://localhost:3065'; const backUrl = process.env.NODE_ENV === 'production' ? 'https://api.nodebird.com' : 'http://localhost:3065'; export { backUrl, domainUrl, localhostUrl }; BACK sagas/user.js // all fork call put delay debounce throttle takeLatest tabkeEvery takeLeding taekMaybe import { all, fork, put, takeLatest, throttle, call } from 'redux-saga/effects'; import axios from 'axios'; // import shortId from 'shortid'; import { LOAD_POSTS_REQUEST, LOAD_POSTS_SUCCESS, LOAD_POSTS_FAILURE, LOAD_USER_POSTS_REQUEST, LOAD_USER_POSTS_SUCCESS, LOAD_USER_POSTS_FAILURE, LOAD_HASHTAG_POSTS_REQUEST, LOAD_HASHTAG_POSTS_SUCCESS, LOAD_HASHTAG_POSTS_FAILURE, LOAD_POST_REQUEST, LOAD_POST_SUCCESS, LOAD_POST_FAILURE, LIKE_POST_REQUEST, LIKE_POST_SUCCESS, LIKE_POST_FAILURE, UNLIKE_POST_REQUEST, UNLIKE_POST_SUCCESS, UNLIKE_POST_FAILURE, ADD_POST_REQUEST, ADD_POST_SUCCESS, ADD_POST_FAILURE, ADD_COMMENT_REQUEST, ADD_COMMENT_SUCCESS, ADD_COMMENT_FAILURE, REMOVE_POST_REQUEST, REMOVE_POST_SUCCESS, REMOVE_POST_FAILURE, UPLOAD_IMAGES_REQUEST, UPLOAD_IMAGES_SUCCESS, UPLOAD_IMAGES_FAILURE, RETWEET_REQUEST, RETWEET_SUCCESS, RETWEET_FAILURE, } from '../reducers/post'; import { ADD_POST_TO_ME, REMOVE_POST_OF_ME, } from '../reducers/user'; function likePostAPI(data) { return axios.patch(`/post/${data}/like`); }; function* likePost(action) { try { const result = yield call(likePostAPI, action.data); yield put({ type: LIKE_POST_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: LIKE_POST_FAILURE, error: err.response.data, }); } } function unlikePostAPI(data) { return axios.delete(`/post/${data}/like`); }; function* unlikePost(action) { try { const result = yield call(unlikePostAPI, action.data); yield put({ type: UNLIKE_POST_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: UNLIKE_POST_FAILURE, error: err.response.data, }); } } function loadPostsAPI(lastId) { return axios.get(`/posts?lastId=${lastId || 0}`); }; function* loadPosts(action) { try { const result = yield call(loadPostsAPI, action.lastId); yield put({ type: LOAD_POSTS_SUCCESS, data: result.data, // data: generateDummyPost(10), }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: LOAD_POSTS_FAILURE, error: err.response.data, }); } } function loadPostAPI(data) { return axios.get(`/post/${data}`); }; function* loadPost(action) { try { const result = yield call(loadPostAPI, action.data); yield put({ type: LOAD_POST_SUCCESS, data: result.data, // data: generateDummyPost(10), }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: LOAD_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 delay(1000); yield put({ type: ADD_COMMENT_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: ADD_COMMENT_FAILURE, error: err.response.data, }); }; }; function addPostAPI(data) { return axios.post('/post', data); }; function* addPost(action) { try { const result = yield call(addPostAPI, action.data); yield put({ type: ADD_POST_SUCCESS, data: result.data }); yield put({ type: ADD_POST_TO_ME, data: result.data.id, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: ADD_POST_FAILURE, error: err.response.data, }); }; }; function removePostAPI(data) { return axios.delete(`/post/${data}`); }; function* removePost(action) { try { const result = yield call(removePostAPI, action.data); yield put({ type: REMOVE_POST_SUCCESS, data: result.data, }); console.log('removePost'); yield put({ type: REMOVE_POST_OF_ME, data: action.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: REMOVE_POST_FAILURE, error: err.response.data, }); }; }; function uploadImagesAPI(data) { return axios.post('/post/images', data); // POST /post/images }; function* uploadImages(action) { try { const result = yield call(uploadImagesAPI, action.data); yield put({ type: UPLOAD_IMAGES_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: UPLOAD_IMAGES_FAILURE, error: err.response.data, }); }; }; function retweetAPI(data) { return axios.post(`/post/${data}/retweet`); // POST /post/images }; function* retweet(action) { try { const result = yield call(retweetAPI, action.data); yield put({ type: RETWEET_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: RETWEET_FAILURE, error: err.response.data, }); }; }; function loadHashtagPostsAPI(data, lastId) { return axios.get(`/hashtag/${data}?lastId=${lastId || 0}`); }; function* loadHashtagPosts(action) { try { const result = yield call(loadHashtagPostsAPI, action.data, action.lastId); yield put({ type: LOAD_HASHTAG_POSTS_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ type: LOAD_HASHTAG_POSTS_FAILURE, error: err.response.data, }); } } function loadUserPostsAPI(data, lastId) { return axios.get(`/user/${data}/posts?lastId=${lastId || 0}`); }; function* loadUserPosts(action) { try { const result = yield call(loadUserPostsAPI, action.data, action.lastId); yield put({ type: LOAD_USER_POSTS_SUCCESS, data: result.data, // data: generateDummyPost(10), }); } catch (err) { console.error(err); yield put({ // put => dispatch 다. type: LOAD_USER_POSTS_FAILURE, error: err.response.data, }); } } function* watchLoadUserPosts() { yield throttle(5000, LOAD_USER_POSTS_REQUEST, loadUserPosts); }; function* watchLoadHashtagPosts() { // 5초에 한번 게사글이 로드 된다. yield throttle(5000, LOAD_HASHTAG_POSTS_REQUEST, loadHashtagPosts); }; function* watchLoadPosts() { // 5초에 한번 게사글이 로드 된다. yield throttle(5000, LOAD_POSTS_REQUEST, loadPosts); }; function* watchLoadPost() { // 5초에 한번 게사글이 로드 된다. yield takeLatest(LOAD_POST_REQUEST, loadPost); }; function* watchRetweet() { // 5초에 한번 게사글이 로드 된다. yield takeLatest(RETWEET_REQUEST, retweet); }; function* watchAddPost() { yield takeLatest(ADD_POST_REQUEST, addPost); }; function* watchUploadImages() { yield takeLatest(UPLOAD_IMAGES_REQUEST, uploadImages); }; function* watchAddComment() { yield takeLatest(ADD_COMMENT_REQUEST, addComment); }; function* watchRemovePost() { yield takeLatest(REMOVE_POST_REQUEST, removePost); }; function* watchLikePost() { yield takeLatest(LIKE_POST_REQUEST, likePost); }; function* watchUnLikePost() { yield takeLatest(UNLIKE_POST_REQUEST, unlikePost); }; export default function* postSaga() { yield all([ fork(watchRetweet), fork(watchUploadImages), fork(watchLikePost), fork(watchUnLikePost), fork(watchAddPost), fork(watchLoadPosts), fork(watchLoadHashtagPosts), fork(watchLoadUserPosts), fork(watchLoadPost), fork(watchRemovePost), fork(watchAddComment), ]); }; reducers/post.js import produce from 'immer'; import { REMOVE_POST_OF_ME } from './user'; export const initialState = { mainPosts: [], imagePaths: [], // 이미지를 업로드 할때 이미지 경로 singlePost: null, postAdded: false, hasMorePosts: true, likePostLoading: false, likePostDone: false, // 추가 likePostError: null, // 추가 retweetLoading: false, retweetDone: false, // 추가 retweetError: null, // 추가 uploadImagesLoading: false, uploadImagesDone: false, // 추가 uploadImagesError: null, // 추가 unlikePostLoading: false, unlikePostDone: false, // 추가 unlikePostError: null, // 추가 loadPostsLoading: false, loadPostsDone: false, // 추가 loadPostsError: null, // 추가 loadPostLoading: false, loadPostDone: false, // 추가 loadPostError: null, // 추가 // 게시글 추가가 완료되었을때 true 로 변한다. postAdded: false, => addPostLoading: false, addPostLoading: false, addPostDone: false, // 추가 addPostError: null, // 추가 addCommentLoading: false, // 댓글 추가가 완료되었을때 true 로 변한다. addCommentDone: false, // 추가 addCommentError: null, // 추가 removePostLoading: false, removePostDone: false, // 추가 removePostError: null, // 추가 }; export const UPLOAD_IMAGES_REQUEST = 'UPLOAD_IMAGES_REQUEST'; export const UPLOAD_IMAGES_SUCCESS = 'UPLOAD_IMAGES_SUCCESS'; export const UPLOAD_IMAGES_FAILURE = 'UPLOAD_IMAGES_FAILURE'; export const RETWEET_REQUEST = 'RETWEET_REQUEST'; export const RETWEET_SUCCESS = 'RETWEET_SUCCESS'; export const RETWEET_FAILURE = 'RETWEET_FAILURE'; 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 LOAD_POST_REQUEST = 'LOAD_POST_REQUEST'; export const LOAD_POST_SUCCESS = 'LOAD_POST_SUCCESS'; export const LOAD_POST_FAILURE = 'LOAD_POST_FAILURE'; export const LOAD_USER_POSTS_REQUEST = 'LOAD_USER_POSTS_REQUEST'; export const LOAD_USER_POSTS_SUCCESS = 'LOAD_USER_POSTS_SUCCESS'; export const LOAD_USER_POSTS_FAILURE = 'LOAD_USER_POSTS_FAILURE'; export const LOAD_HASHTAG_POSTS_REQUEST = 'LOAD_HASHTAG_POSTS_REQUEST'; export const LOAD_HASHTAG_POSTS_SUCCESS = 'LOAD_HASHTAG_POSTS_SUCCESS'; export const LOAD_HASHTAG_POSTS_FAILURE = 'LOAD_HASHTAG_POSTS_FAILURE'; export const LIKE_POST_REQUEST = 'LIKE_POST_REQUEST'; export const LIKE_POST_SUCCESS = 'LIKE_POST_SUCCESS'; export const LIKE_POST_FAILURE = 'LIKE_POST_FAILURE'; export const UNLIKE_POST_REQUEST = 'UNLIKE_POST_REQUEST'; export const UNLIKE_POST_SUCCESS = 'UNLIKE_POST_SUCCESS'; export const UNLIKE_POST_FAILURE = 'UNLIKE_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 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_IMAGE = 'REMOVE_IMAGE'; export const addComment = (data) => ({ type: ADD_COMMENT_REQUEST, data, }); export const addPost = (data) => ({ type: ADD_POST_REQUEST, data, }); export const removePost = (data) => ({ type: REMOVE_POST_OF_ME, data, }); const reducer = (state = initialState, action) => produce(state, (draft) => { switch (action.type) { case REMOVE_IMAGE: draft.imagePaths = draft.imagePaths.filter((v, i) => i !== action.data); break; case RETWEET_REQUEST: draft.retweetLoading = true; draft.retweetDone = false; draft.retweetError = null; break; case RETWEET_SUCCESS: draft.retweetLoading = false; draft.retweetDone = true; draft.mainPosts.unshift(action.data); break; case RETWEET_FAILURE: draft.retweetLoading = false; draft.retweetError = action.error; break; case UPLOAD_IMAGES_REQUEST: draft.uploadImagesLoading = true; draft.uploadImagesDone = false; draft.uploadImagesError = null; break; case UPLOAD_IMAGES_SUCCESS: { draft.imagePaths = action.data; draft.uploadImagesLoading = false; draft.uploadImagesDone = true; break; } case UPLOAD_IMAGES_FAILURE: draft.uploadImagesLoading = false; draft.uploadImagesError = action.error; break; case LIKE_POST_REQUEST: draft.likePostLoading = true; draft.likePostDone = false; draft.likePostError = null; break; case LIKE_POST_SUCCESS: { const post = draft.mainPosts.find((v) => v.id === action.data.PostId); post.Likers.push({ id: action.data.UserId }); draft.likePostLoading = false; draft.likePostDone = true; break; } case LIKE_POST_FAILURE: draft.likePostLoading = false; draft.likePostError = action.error; break; case UNLIKE_POST_REQUEST: draft.unlikePostLoading = true; draft.unlikePostDone = false; draft.unlikePostError = null; break; case UNLIKE_POST_SUCCESS: { console.log(action.data); const post = draft.mainPosts.find((v) => v.id === action.data.PostId); post.Likers = post.Likers.filter((v) => v.id !== action.data.UserId); // 제거 draft.unlikePostLoading = false; draft.unlikePostDone = true; break; } case UNLIKE_POST_FAILURE: draft.unlikePostLoading = false; draft.unlikePostError = action.error; break; case LOAD_USER_POSTS_REQUEST: case LOAD_HASHTAG_POSTS_REQUEST: case LOAD_POSTS_REQUEST: draft.loadPostsLoading = true; draft.loadPostsDone = false; draft.loadPostsError = null; break; case LOAD_USER_POSTS_SUCCESS: case LOAD_HASHTAG_POSTS_SUCCESS: case LOAD_POSTS_SUCCESS: draft.loadPostsLoading = false; draft.loadPostsDone = true; draft.mainPosts = draft.mainPosts.concat(action.data); draft.hasMorePosts = action.data.length === 10; break; case LOAD_USER_POSTS_FAILURE: case LOAD_HASHTAG_POSTS_FAILURE: case LOAD_POSTS_FAILURE: draft.loadPostsLoading = false; draft.loadPostsError = action.error; break; 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.singlePost = action.data; 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(action.data); draft.imagePaths = []; break; case ADD_POST_FAILURE: draft.addPostLoading = true; draft.addPostError = action.error; break; case ADD_COMMENT_REQUEST: draft.addCommentLoading = true; draft.addCommentDone = false; draft.addCommentError = null; break; case ADD_COMMENT_SUCCESS: // action.data.content, action.data.postId, action.data.userId // post.Comments.unshift(dummyComment(action.data.content)); const post = draft.mainPosts.find((v) => v.id === action.data.PostId); post.Comments.unshift(action.data); draft.addCommentLoading = false; draft.addCommentDone = true; break; case ADD_COMMENT_FAILURE: draft.addCommentLoading = false; draft.addCommentError = action.error; break; case REMOVE_POST_REQUEST: draft.removePostLoading = true; draft.removePostDone = false; draft.removePostError = null; break; // [ !== 일치하는 게시글만 지운다. ] 그리고 [ === 일치하는 게시글 이외의 모든 게시글이 지워진다. ] // filter를 사용해서 불변성을 유지한다. case REMOVE_POST_SUCCESS: draft.removePostLoading = false; draft.removePostDone = true; draft.mainPosts = draft.mainPosts.filter((v) => v.id !== action.data.PostId); break; case REMOVE_POST_FAILURE: draft.removePostLoading = false; draft.removePostError = action.error; break; default: break; } }); export default reducer; reducers/user.js import produce from 'immer'; export const initialState = { removeFollowerLoading: false, // 내가 수락한 친구 차단하기 removeFollowerDone: false, // 추가 removeFollowerError: null, // 추가 loadUserLoading: false, // 사용자 정보 가져오기 시도중.. 로딩창을 띄운다. loadUserDone: false, loadUserError: null, loadMyInfoLoading: false, // 내 정보 가져오기 시도중.. 로딩창을 띄운다. loadMyInfoDone: false, loadMyInfoError: null, logInLoading: false, // 로그인 시도중.. 로딩창을 띄운다. logInDone: false, logInError: null, logOutLoading: false, // 로그아웃 시도중.. 로딩창을 띄운다. logOutDone: false, logOutError: null, followLoading: false, // 팔로우 시도중.. 로딩창을 띄운다. followDone: false, followError: null, unfollowLoading: false, // 언팔로우 시도중.. 로딩창을 띄운다. unfollowDone: false, unfollowError: null, loadFollowersLoading: false, // 팔로워 목록 가져오기 시도중.. 로딩창을 띄운다. loadFollowersDone: false, loadFollowersError: null, loadFollowingsLoading: false, // 팔로윙 목록 가져오기 시도중.. 로딩창을 띄운다. loadFollowingsDone: false, loadFollowingsError: null, signUpLoading: false, // 회원가입 시도중.. 로딩창을 띄운다. signUpDone: false, signUpError: null, changeNicknameLoading: false, // 닉네임 변경 시도중.. 로딩창을 띄운다. changeNicknameDone: false, changeNicknameError: null, me: null, userInfo: null, }; export const REMOVE_FOLLOWER_REQUEST = 'REMOVE_FOLLOWER_REQUEST'; export const REMOVE_FOLLOWER_SUCCESS = 'REMOVE_FOLLOWER_SUCCESS'; export const REMOVE_FOLLOWER_FAILURE = 'REMOVE_FOLLOWER_FAILURE'; export const LOAD_MY_INFO_REQUEST = 'LOAD_MY_INFO_REQUEST'; export const LOAD_MY_INFO_SUCCESS = 'LOAD_MY_INFO_SUCCESS'; export const LOAD_MY_INFO_FAILURE = 'LOAD_MY_INFO_FAILURE'; export const LOAD_USER_REQUEST = 'LOAD_USER_REQUEST'; export const LOAD_USER_SUCCESS = 'LOAD_USER_SUCCESS'; export const LOAD_USER_FAILURE = 'LOAD_USER_FAILURE'; 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 LOAD_FOLLOWERS_REQUEST = 'LOAD_FOLLOWERS_REQUEST'; export const LOAD_FOLLOWERS_SUCCESS = 'LOAD_FOLLOWERS_SUCCESS'; export const LOAD_FOLLOWERS_FAILURE = 'LOAD_FOLLOWERS_FAILURE'; export const LOAD_FOLLOWINGS_REQUEST = 'LOAD_FOLLOWINGS_REQUEST'; export const LOAD_FOLLOWINGS_SUCCESS = 'LOAD_FOLLOWINGS_SUCCESS'; export const LOAD_FOLLOWINGS_FAILURE = 'LOAD_FOLLOWINGS_FAILURE'; export const ADD_POST_TO_ME = 'ADD_POST_TO_ME'; export const REMOVE_POST_OF_ME = 'REMOVE_POST_OF_ME'; export const ADD_COMMENT_TO_ME = 'ADD_COMMENT_TO_ME'; export const REMOVE_COMMENT_OF_ME = 'REMOVE_COMMENT_OF_ME'; const reducer = (state = initialState, action) => produce (state, (draft) => { switch (action.type) { case REMOVE_FOLLOWER_REQUEST: draft.removeFollowerLoading = true; draft.removeFollowerDone = false; draft.removeFollowerError = null; break; case REMOVE_FOLLOWER_SUCCESS: { draft.removeFollowerLoading = false; draft.me.Followers = draft.me.Followers.filter((v) => v.id !== action.data.UserId); draft.removeFollowerDone = true; break; } case REMOVE_FOLLOWER_FAILURE: draft.removeFollowerLoading = false; draft.removeFollowerError = action.error; break; case LOAD_MY_INFO_REQUEST: draft.loadMyInfoLoading = true; draft.loadMyInfoError = null; draft.loadMyInfoDone = false; break; case LOAD_MY_INFO_SUCCESS: draft.loadMyInfoLoading = false; draft.me = action.data; draft.loadMyInfoDone = true; break; case LOAD_MY_INFO_FAILURE: draft.loadMyInfoLoading = false; // isLoggingOut: true, => logOutLoading: true, draft.loadMyInfoError = action.error; // logInError: action.error, => logOutDone: false, break; case LOAD_USER_REQUEST: draft.loadUserLoading = true; draft.loadUserError = null; draft.loadUserDone = false; break; case LOAD_USER_SUCCESS: draft.loadUserLoading = false; draft.userInfo = action.data; draft.loadUserDone = true; break; case LOAD_USER_FAILURE: draft.loadUserLoading = false; // isLoggingOut: true, => logOutLoading: true, draft.loadUserError = action.error; // logInError: action.error, => logOutDone: false, break; case LOAD_FOLLOWERS_REQUEST: draft.loadFollowersLoading = true; draft.loadFollowersError = null; draft.loadFollowersDone = false; break; case LOAD_FOLLOWERS_SUCCESS: draft.loadFollowersLoading = false; draft.me.Followers = action.data; draft.loadFollowersDone = true; break; case LOAD_FOLLOWERS_FAILURE: draft.loadFollowersLoading = false; draft.loadFollowersError = action.error; break; case LOAD_FOLLOWINGS_REQUEST: draft.loadFollowingsLoading = true; draft.loadFollowingsError = null; draft.loadFollowingsDone = false; break; case LOAD_FOLLOWINGS_SUCCESS: draft.loadFollowingsLoading = false; draft.me.Followings = action.data; draft.loadFollowingsDone = true; break; case LOAD_FOLLOWINGS_FAILURE: draft.loadFollowingsLoading = false; draft.loadFollowingsError = action.error; break; case FOLLOW_REQUEST: draft.followLoading = true; draft.followError = null; draft.followDone = false; break; case FOLLOW_SUCCESS: draft.followLoading = false; draft.me.Followings.push({ id: action.data.UserId }); draft.followDone = true; break; case FOLLOW_FAILURE: draft.followLoading = false; // isLoggingOut: true, => logOutLoading: true, draft.followError = action.error; // logInError: action.error, => logOutDone: false, break; case UNFOLLOW_REQUEST: draft.unfollowLoading = true; draft.unfollowError = null; draft.unfollowDone = false; break; case UNFOLLOW_SUCCESS: draft.unfollowLoading = false; draft.unfollowDone = true; draft.me.Followings = draft.me.Followings.filter((v) => v.id !== action.data.UserId ); break; case UNFOLLOW_FAILURE: draft.unfollowLoading = false; // isLoggingOut: true, => logOutLoading: true, draft.unfollowError = action.error; // logInError: action.error, => logOutDone: false, break; case CHANGE_NICKNAME_REQUEST: draft.changeNicknameLoading = true; // 닉네임 변경 시도중이니까 => 버튼 로딩 O draft.changeNicknameDone = false; // 닉네임 변경중 draft.changeNicknameError = null; break; case CHANGE_NICKNAME_SUCCESS: draft.me.nickname = action.data.nickname; draft.changeNicknameLoading = false; // 닉네임 변경 요청이 성공했으니까 => 버튼 로딩 X draft.changeNicknameDone = true; // 닉네임 변경 완료 break; case CHANGE_NICKNAME_FAILURE: draft.changeNicknameLoading = false; // 닉네임 변경 요청이 끝났으니까 => 버튼 로딩 X draft.changeNicknameError = action.error; break; case SIGN_UP_REQUEST: draft.signUpLoading = true; // 회원가입 시도중이니까 => true isLoggingOut: true, => logInLoading: true, draft.signUpDone = false; draft.signUpError = null; break; case SIGN_UP_SUCCESS: draft.signUpLoading = false; // 회원가입 요청이 성공했으니까 => false isLoggingOut: false, => logOutLoading: false, draft.signUpDone = true; // isLoggedIn: false, => logOutDone: true, break; case SIGN_UP_FAILURE: draft.signUpLoading = false; // 회원가입 요청이 끝났으니까 => false isLoggingOut: false, => logOutLoading: false, draft.signUpError = action.error; // 추가 break; case LOG_IN_REQUEST: draft.logInLoading = true; draft.logInError = null; draft.logInDone = false; break; case LOG_IN_SUCCESS: draft.logInLoading = false; draft.logInDone = true; draft.me = action.data; break; case LOG_IN_FAILURE: draft.logInLoading = false; // isLoggingOut: true, => logOutLoading: true, draft.logInError = action.error; // logInError: action.error, => logOutDone: false, break; case LOG_OUT_REQUEST: draft.logOutLoading = true; // 로그아웃 시도중이니까 => true draft.logOutDone = false; draft.logOutError = null; break; case LOG_OUT_SUCCESS: draft.logOutLoading = false; // 로그아웃 요청이 성공했으니까 => false isLoggingOut: false, => logOutLoading: false, draft.logOutDone = true; // isLoggedIn: false, => logOutDone: true, draft.me = null; break; case LOG_OUT_FAILURE: draft.isLoggingOut = false; // 요청이 끝났으니까 => false isLoggingOut: false, => logOutLoading: false, draft.logOutError = action.error; // 추가 break; case ADD_POST_TO_ME: draft.me.Posts.unshift({ id: action.data }); break; case REMOVE_POST_OF_ME: draft.me.Posts = draft.me.Posts.filter((v) => v.id !== action.data); break; default: break; } }); export default reducer;