묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결유니티(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;
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 기본 강의
로그인후 앱 크러쉬
https://github.com/lhj1004ss/LoginAndRegister_react-node ERROR: Cannot set headers after they are sent to the client 포스트맨으로 로인후에 유저토큰만 완성되고 바로 앱이 크러쉬됩니다. 구글링을 좀해보니, 이 에러가 보통 콜백이 서버에서의 아웃풋이 클라이언트로 생각했던것보다? 일찍 갔을 때 나오거나 콜백을 두번불렀을 때 나오는 에러라고 하는데, 코드를 검토해도찾을 수 없어서 여기에 올립니다!
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 쇼핑몰 사이트 만들기[전체 리뉴얼]
카트페이지에서 quantity만 못가져오는데요 왜그런걸까요 ?
스테잇을 확인하면 quantity 부분이 빠져있는데 어디를 확인해야 할지 모르겠네요. 도와주세요! 감사합니다 깃헙주소입니다: https://github.com/vladastam/shop_app
-
미해결파이썬 사용자를 위한 웹개발 입문 A to Z Django + Bootstrap
tdd 테스트코드 작성 B에서 아래와 같은 에러가 납니다.
test 누르면 아직 게시물이 없습니다. 에서 자꾸 에러가 나요. (venv) C:\Users\user\Desktop\HTML+django\my_django>python manage.py test Creating test database for alias 'default'... System check identified no issues (0 silenced). F ====================================================================== FAIL: test_post_list (blog.tests.TestView) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\Users\user\Desktop\HTML+django\my_django\blog\tests.py", line 30, in test_post_list self.assertIn('아직 게시물이 없습니다.', soup.body.text) AssertionError: '아직 게시물이 없습니다.' not found in '\n\n\nBootswatch\n\n\n\n\n\n\nThemes \n\nDefault\n\nCerulean\nCosmo\nCyborg\nDarkly\nFlatly\nJournal\nLitera\nLumen\nLux\nMateria\nMinty\nPulse\nSandstone\nSimplex\nSketchy\nSlate\nSolar\nSpacelab\nSuperhero\nUnited\nYeti\n\n\n\nHelp\n\n\nBlog\n\n\nFlatly \n\nOpen in JSFiddle\n\nbootstrap.min.css\nbootstrap.css\n\n_variables.scss\n_bootswatch.scss\n\n\n\n\n\n\n\n\n\n\nBlog\nby matiii\n' ---------------------------------------------------------------------- Ran 1 test in 0.037s FAILED (failures=1) Destroying test database for alias 'default'... post_list.html <div class="col-md-8"> <h1 class="my-4">Blog</h1> <small>by matiii</small> </h1> <!-- Blog Post --> {% if objects_list.exist %} {% for p in object_list %} <div class="card mb-4"> {% if p.head_image %} <img class="card-img-top" src="{{ p.head_image.url }}" alt="Card image cap"> {% else %} <img class="card-img-top" src="https://picsum.photos/750/300/?random" alt="Card image cap"> {% endif %} <div class="card-body"> <h2 class="card-title">{{ p.title }}</h2> <p class="card-text">{{ p.content | truncatewords:50 }}</p> <a href="#" class="btn btn-primary">Read More →</a> </div> <div class="card-footer text-muted"> Posted on {{p.created}} <a href="#">{{p.author}}</a> </div> </div> <!-- Pagination --> <ul class="pagination justify-content-center mb-4"> <li class="page-item"> <a class="page-link" href="#">← Older</a> </li> <li class="page-item disabled"> <a class="page-link" href="#">Newer →</a> </li> </ul> {% endfor %} {% else %} <h3>아직 게시물이 없습니다.</h3> {% endif %}</div> tests.py from django.test import TestCase# Create your tests here.from django.test import TestCase, Clientfrom bs4 import BeautifulSoupfrom .models import Postfrom django.utils import timezonefrom django.contrib.auth.models import Userclass TestView(TestCase): def setUp(self): self.client = Client() self.author_OOO=User.objects.create(username='SAM', password='none') def test_post_list(self): response = self.client.get('/blog/') self.assertEqual(response.status_code, 200) soup = BeautifulSoup(response.content, 'html.parser') title = soup.title self.assertEqual(title.text, 'Blog') navbar = soup.find('div', id='navbar') self.assertIn('Blog', navbar.text) self.assertIn('Help', navbar.text) self.assertEqual(Post.objects.count(), 0) self.assertIn('아직 게시물이 없습니다.', soup.body.text) post_OOO = Post.objects.create( title='The First Post', content='Hello World!', created=timezone.now(), author=self.author_OOO, ) self.assertGreater(Post.objects.count(), 0) response = self.client.get('/blog/') self.assertEqual(response.status_code, 200) soup = BeautifulSoup(response.content, 'html.parser') body = soup.body self.assertNotIn('아직 게시물이 없습니다.', body.text) self.assertIn(post_OOO.title, body.text)
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
H2실행
안녕하세요 강사님 !H2실행이 안돼서 여러가지 방법을 시도해봤는데 실행이 안되네요.. 브라우저 창이 열리지않고 아래 사진과 같이 보여지고 종료되는데 혹시 이유 아신다면 알려주시면 감사하겠습니다
-
미해결모의해킹 실무자가 알려주는, SQL Injection 공격 기법과 시큐어 코딩 : PART 1
대응방안 코드에 대해서 질문이 있습니다.
안녕하세요. 강의 "대응 방안" 파트의 "상세 대응 방안(2)" 강의를 보던 중 궁금한점이 생겨서 질문드립니다. 1) 첫째로, 문자 입력에 대한 대응 방안으로 강의에서 예시로 제시했던 코드가 아래와 같습니다. --------------------------------------------------------------------------- JAVA String keyword = request.getParameter("keyword"); // MSSQL, ORACLE 대응 방안 예시 keyword = keyword.replace("'", "''"); <<<<<<<<< (1) keyword = keyword.replace("\"", "\"\""); query = "select * from board where keyword like '%" + keyword + "%'"; ------------------------------------------------------------------------------- 이 부분에서 <<<<<<<< (1) 표시된 부분의 내용이 잘 이해가 되지 않아서요. 강의 하시면서 공격자가 '(작음따옴표) 하나를 입력하면 두개로 변하여 '(작은따옴표)가 검색이 된다고 말씀하셨는데요 만약 공격자가 '(작은따옴표) 하나를 입력한 경우라면 이 하나의 '(작은따옴표)가 연속된 두개의 ''(작은 따옴표)로 변하여 query 는 다음과 같이 생성될 것입니다. select * from board where keyword like '%''%' 이런식으로 되면 % 양쪽으로 그냥 '(작은따옴표)로 깜싸는 정도로 바뀔거라고 짐작하고 있는데요. 어떻게 '(작은따옴표)도 검색이 가능하게 되는지 이해가 되지 않습니다. 그리고 이 경우 mysql 경우 처럼 \' 패턴을 이용하면 우회가 가능한지도 궁금합니다. 그리고.... 2) 두번째로, 컬럼/테이블 입력에 대한 대응 방안으로 제시한 예제 코드의 일부는 다음과 같습니다. boolean flag = Pattern.matches("^[0-9a-zA-Z-]*$", tb_name); 강의에서 설명해주셨던 것 처럼 이 코드 내용은 숫자, 알파벳 대소문자 그리고 -(대시 또는 하이픈)문자를 필터링하는 것인데요. 제 생각에는 -(대시) 문자 이외의 _(언더바) 문자가 추가되어야 하지 않을까 해서요? 강의에서 사용하였던 "TB_BOARD" 처럼 _(언더바) 문자가 포함된 테이블이나 컬럼이 존재하는거로 봐서는요, 아니면 제시된 코드의 오타인걸로도 생각이 들고요. 감사합니다~
-
해결됨스프링 시큐리티
IP 제어 관련 문의 드립니다.
안녕하세요.. 현재 강의를 듣고 있는데요. Client IP 접근을 제어해서, 자원에 접근이 안되도록 하는 데모를 보았습니다. 이 기능을 사용할 경우, WAS 앞단에 L4 나 Proxy 와 같은 장치가 있어도, Client IP 를 정상적으로 인식 할 수 있나요? 혹시, L4 나 Proxy 가 있는 경우, 사용자의 Client IP 가 아니고, L4 IP 가 전달되지 않는 지 문의드립니다.
-
미해결자바 스프링 프레임워크(renew ver.) - 신입 프로그래머를 위한 강좌
강의자료는 없나요?????
3강 듣고있는데 이거 혹시 강의자료는 없나요???
-
해결됨Vue.js 완벽 가이드 - 실습과 리팩토링으로 배우는 실전 개념
아무리 찾아도답이안나와서 질문드립니다.
https://codepen.io/mikilll94/pen/RwbYrpz 간단한 예제인데요. 데이터가 많을때 v-model 바인딩을 하면 속도가 엄청느려지는데 이유가 뭔가요 v-model 동작방식과 관련이 있을까요??.. 그리고 해결방안이 있을까요
-
해결됨React로 NodeBird SNS 만들기
like, unlike
안녕하세요. 제로초님 다름이 아니라 axios like에 return axios.post(`/post/${postId}/like`, {}, { withCredentials: true }); 이렇게 하면 잘 날라가는데 return axios.delete(`/post/${postId}/like`, {}, { withCredentials: true }); 이렇게 unlike는 빈 데이터를 보내면 401 에러가 뜨는데 그 에러가 로그인 안했다는 isLoggedin 그 에러거든요? 근데 로그인 정보랑 다 들어있고 해서 의아했는데 저 빈 객체 를 없애니깐 잘 동작하더라고요. 이거 왜이러는걸까요?
-
미해결React로 NodeBird SNS 만들기
2020.08.09 antd
import React, { useState } from 'react'; import AppLayout from "../components/AppLayout"; import Head from "next/head"; import { Form, Input, Checkbox, Button } from 'antd'; const Signup = () => { const [id, setId] = useState(''); const [nick, setNick] = useState(''); const [password, setPassword] = useState(''); const [passwordCheck, setPasswordCheck] = useState(''); const [term, setTerm] = useState(false); const [passwordError, setPasswordError] = useState(false); const [termError, setTermError] = useState(false); const onFinish= () => { if (password !== passwordCheck) { return setPasswordError(true); } if (!term) { return setTermError(true); } console.log({ id, nick, password, passwordCheck, term, }); }; const onChangeId = (e) => { setId(e.target.value); }; const onChangeNick = (e) => { setNick(e.target.value); }; const onChangePassword = (e) => { setPassword(e.target.value); }; const onChangePasswordChk = (e) => { setPasswordError(e.target.value !== password); setPasswordCheck(e.target.value); }; const onChangeTerm = (e) => { setTermError(false); setTerm(e.target.checked); }; return ( <> <Head> <title>NodeBird</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/antd/3.16.2/antd.css" /> </Head> <AppLayout> <Form onFinish={onFinish} style={{ padding: 10 }}> <Form.Item label={"아이디"} name={"user-id"} rules={[{ required: true, message: "Please input your user ID!"}]} > <Input name="user-id" value={id} required onChange={onChangeId} /> </Form.Item> <Form.Item label={"닉네임"} name={"user-nick"} rules={[{ required: true, message: "Please input your nickname!"}]} > <Input name="user-nick" value={nick} required onChange={onChangeNick} /> </Form.Item> <Form.Item label={"비밀번호"} name={"user-password"} rules={[{ required: true, message: "Please input your password!"}]} > <Input name="user-password" type={"password"} value={password} required onChange={onChangePassword} /> </Form.Item> <Form.Item label={"비밀번호 체크"} name={"user-password-check"} > <Input name="user-password-check" type={"password"} value={passwordCheck} required onChange={onChangePasswordChk} /> {passwordError && <div style={{ color: 'red' }}>비밀번호가 일치하지 않습니다.</div>} </Form.Item> <Form.Item name={"user-term"}> <Checkbox name={"user-term"} checked={term} onChange={onChangeTerm}>서비스 이용 동의</Checkbox> {termError && <div style={{ color: 'red' }}>약관에 동의하셔야 합니다.</div>} </Form.Item> <Form.Item> <Button type="primary" htmlType="submit">가입하기</Button> </Form.Item> </Form> </AppLayout> </> ); }; export default Signup;
-
미해결it 취업을 위한 알고리즘 문제풀이 입문 (with C/C++) : 코딩테스트 대비
cin/cout이 더 낫지 않을까요
c++로 통일하는게 낫다고 봅니다.
-
미해결실전 리액트 프로그래밍
자식 컴포넌트 props 문의 드립니다.
강사님 안녕하세요. 오늘도 영상 시청하던 중, 궁금한 점이 하나 생겨서 문의드립니다. 부모 컴포넌트에서 useSelector 로 얻은 상태값 일부를 자식 컴포넌트에 props 로 전달하여 자식컴포넌트에서 활용하는 식으로 코딩하는 과정을 확인하게 됐는데요. 자식컴포넌트에서 직접 useSelector 를 사용하여 얻는 것과 어떤 차이점이 있을까요?일단, props 로 내려보내는 방식의 경우, 자식컴포넌트가 특정 리덕스 state 에 의존하지 않게 되므로 다른 부모컴포넌트에서 재활용할 수 있을 것 같아보이는데요. 만약 자식 컴포넌트를 재활용할 일이 없는 경우에는 자식 쪽에서 직접 useSelector 를 사용하는 방법이 props 를 이용하는 것과 또 다른 차이가 있을까요?
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 유튜브 사이트 만들기
heroku deploy
안녕하세요 강사님 제 로컬 서버에서는 페이지 작동이 잘되는데 헤로쿠에 올려보려 하니 이런 에러가 계속 떠서요! 2020-08-09T14:29:32.555557+00:00 app[web.1]: Error: ENOENT: no such file or directory, stat '/app/client/build/index.html' 2020-08-09T14:29:32.555899+00:00 heroku[router]: at=info method=GET path="/" host=seoul-tube.herokuapp.com request_id=99ff7d0c-8a4b-4399-a2bb-624cc8eca90b fwd="222.98.69.5" dyno=web.1 connect=0ms service=22ms status=404 bytes=412 protocol=https 2020-08-09T14:30:00.270232+00:00 app[web.1]: MongooseError [MongooseServerSelectionError]: connect ECONNREFUSED 127.0.0.1:27017 index.html파일을 못 찾는 것 같아 수정해보려고 하는데 폴더 구조를 client/public => client/build로 바꿨는데도 똑같아서 어찌 해야 할지 여쭤봅니다. 그리고 저희 구조 상에서는 build폴더가 안 보이는데 로컬에서는 잘 작동하는 게 신기한데 build폴더는 webpack실행 후 public폴더가 압축되서 만들어지고 눈에 안 보이더라도 실행되는 폴더인가요?