수강이 제한됩니다.
다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결React로 NodeBird SNS 만들기
오늘 하루 동안 쿠키/세션에 대해서 있었던 문제들입니다..
d
- 미해결React로 NodeBird SNS 만들기
this. set-cookie domain attribute was invalid with regards to the current host URL
IP로도 해보고 무료 도메인으로 domain: '.snsservice.tk' 이런 식으로 점 찍어서 해도 안되는데 해결을 못하겠습니다 ㅠㅠ
- React로 NodeBird SNS 만들기
IP로만은 set-cookie가 안되는건가요?
삭제된 글입니다
- 미해결React로 NodeBird SNS 만들기
belongsTo에 의해 생겨난 Id에 대한 질문
6:58초쯤 내용인데요, 제가 Sql 기본기가 없어서 질문드립니다. belongsTo를 하면서 UserId, ReweetId가 생기는 건 이해했는데요, 저 UserId라는게 User테이블에 자동으로 붙는 id를 갖고 온거 맞나요? 제가 foreignKey랑 좀 헷갈리는 것 같네요
- 미해결React로 NodeBird SNS 만들기
axios timeout 관련 질문
배포를 하고나서 API 서버를 안켜두니 timeout error가 발생하더라구요 axios.post를 try catch 로 감싸서 처리하는게 제일 좋은 방법인가요?
- 미해결React로 NodeBird SNS 만들기
리덕스 대신 mobx 로 진행하는 프로젝트도 부탁드립니다.
리덕스로 진행하려고 하다 현재 멤버들이 모두 자바개발자이고 어노테이션에 익숙한 사람들이라 mobx를 선호하게 되었습니다. 쉽고 간편하다는 이유도 있었구요. 현재는 훅 기반으로 펑션위주의 개발을 하고 있고 mobx로 상태관리 및 SSR을 적용해서 개발하는데 아무래도 자료가 많지않아 힘들네요. mobx 프로젝트도 많이 해보신것 같아 질문은 아니지만 의향을 전해봅니다~ 강의 항상 감사드려요~~
- 해결됨React로 NodeBird SNS 만들기
passport 구조 질문드립니다.
오늘 좀 질문이 많네요. 죄송합니다! back / index.js ↓ passport/ index.js : id에 맞는 유저를 db에서 찾음 ↓ passport/local.js : index.js에서 찾은 유저에 대한 userId와 password를 비교 ↓ routes/ user.js : authenticate과정으로 에러나 서버오류가 없을 시, req.login을 받고 res.json 해줌 이 순서로 가는 것 같은데, 제가 틀린부분이나 잘못알고 있는 부분이 있을까요? 혹시 보강설명도 해주시면 감사드리겠습니다. 제가 처음보는 부분이라 도큐먼트랑 같이봐도 전체적으로 파악이 잘안되네요
- 해결됨React로 NodeBird SNS 만들기
db에서 through로 설장한 table이 생성이 안됩니다.
through된 부분도 강의 12:10에 보면 테이블로 만들어져 있는데 저는 그게 없는데 원인을 뭘로 볼 수 있을까요? (follow, like, posthashtag이런게 없습니다. 딱 js로 만든 다섯개만 테이블로 나와요) User.js 코드 module.exports = (sequelize, DataTypes) => { const User = sequelize.define( "User", { nickname: { type: DataTypes.STRING(20), allowNull: false, }, userId: { type: DataTypes.STRING(20), allowNull: false, unique: true, }, password: { type: DataTypes.STRING(100), allowNull: false, }, }, { charset: "utf8", collate: "utf8_general_ci", // can use Korean } ); User.associate = (db) => { db.User.hasMany(db.Post, { as: "Posts" }); db.User.hasMany(db.Comment); db.User.belongsToMany(db.Post, { through: "Like", as: "Liked" }); db.User.belongsToMany(db.User, { through: "Follow", as: "Followers" }); db.User.belongsToMany(db.User, { through: "Follow", as: "Followings" }); }; return User; }; Post.js 코드 module.exports = (sequelize, DataTypes) => { const Post = sequelize.define( "Post", { content: { type: DataTypes.TEXT, allowNull: false, }, }, { charset: "utf8mb4", collate: "utf8mb4_general_ci", // can use Korean } ); Post.associate = (db) => { db.Post.belongsTo(db.User); db.Post.belongsToMany(db.User, { through: "Like", as: "Likers" }); db.Post.belongsTo(db.Post, { as: "Retweet" }); db.Post.hasMany(db.Comment); db.Post.hasMany(db.Image); db.Post.belongsToMany(db.Hashtag, { through: "PostHashtag" }); }; return Post; }; index.js 코드 const Sequelize = require("sequelize"); const env = process.env.NODE_ENV || "development"; const config = require("../config/config")[env]; const db = {}; const sequelize = new Sequelize( config.database, config.username, config.password, config ); Object.keys(db).forEach((modelName) => { if (db[modelName].associate) { db[modelName].associate(db); } }); db.Comment = require("./comment")(sequelize, Sequelize); db.Hashtag = require("./hashtag")(sequelize, Sequelize); db.Image = require("./image")(sequelize, Sequelize); db.Post = require("./post")(sequelize, Sequelize); db.User = require("./user")(sequelize, Sequelize); db.sequelize = sequelize; db.Sequelize = Sequelize; module.exports = db;
- 해결됨React로 NodeBird SNS 만들기
dotenv.config() 두번해야하는 이유?
config.js에 dotenv.config()를 하고 index.js에도 dotenv.config()를 하는데 두번 다 해야하는건가요?
- 해결됨React로 NodeBird SNS 만들기
7:01초 쯤에 async내에 있는 인자들이 조금 헷갈리는데요
async내에 있는 userId, password 이 두개가 프론트에서 넘어오는 과정이 조금 헷갈려서 질문드립니다. dispatch => generator API함수의 인자 => 그리고 지금async 인자 위 3단계로 넘어온걸로 이해하면 되는거죠??
- 미해결React로 NodeBird SNS 만들기
next link에 관련된 질문입니다.
제로초님 강의 항상 잘 보고있습니다. 제로초님의 강의를 들으면서 제 스스로 공부를 하고있는데, onDetail 는 onClick에 사용되어지고 있습니다. onClick={onDetail} <- 이렇게 되어있습니다 const onDetail = () => { console.log(`onDetail id => ${id}`); return Router.push({ pathname: `/detail`, query: { movieId : parseInt(id) }}, `/detail/movie/${parseInt(id)}`); }; 위와 같은 형식으로 Router.push를 만들어 놓고 query로 데이터 전송을 할려고합니다. 전송할 페이지는 detail 입니다. 예로들면 id의 234이라는 숫자가 있습니다. id를 movieId라는 변수에 담고 데이터를 전달할려고 합니다. (위에 id는 값은 정상적으로 움직입니다. ) 그리고, pages/details에서 넘겨준 데이터(movieId )를 받을려고 합니다. import React from 'react'; const Detail = ({ movieId }) => { console.log(`movieId = ${movieId}`); return ( <div> Detail </div> ); }; export default Detail; 위와 같이 console.log를 찍어보면 undefined가 나옵니다. 분명히 query로 전달하였고, query의 이름명이 movieId이고, 데이터 전달 받는 쪽도 movieId인데 Detail의 페이지에서 movieId가 데이터를 왜 못 받은지 알고싶습니다. 그리고, 잘못된 이유도 알고싶습니다.
- 미해결React로 NodeBird SNS 만들기
https 적용후
프론트 서버 로그입니다. 로그인이 되지 않습니다. 백단은 문제없이 돌아갑니다.
- 미해결React로 NodeBird SNS 만들기
saga axios.get 주소질문...............
https://www.inflearn.com/questions/33218 다시 새롭게 질문드립니다,. 프론트상의 요청주소를 "localhost:3060/post/100000(그룹id)" 로 하려고 전반적으로 수정하였고 부모자식관계가 있는 댓글부분을 참고해서 < routes / back>, < sagas / front > 거의 똑같이 만들었어요 "(게시물(Post)의 부모가되는) GpostId 를 찾아서 게시물들 불러오기" 를 하고싶어서 아래와같이 코드를 작성했는데 posts/ undefined 가 뜹니다. saga 에서 loadMainPostsApi 에서 변수 gpostId를 제대로 정의하지못하는것같습니다.. ****** 댓글올리기 사이클이랑 거의 동일하게 해주었는데 ( 초록색빗금표시를 한부분의 코드 ) 게시물불러오기가 안되는 이유가 뭘까요ㅠ?? ****** < posts.js/ routes / back > // 게시물'들' 불러오기 router.get('/:id', async (req, res, next) => { // GET /api/posts/100/개발자 try { const gpost = await db.Gpost.findOne({ where: { id: req.params.id } }); if (!gpost) { return res.status(404).send('포스트가 존재하지 않습니다.!!!!'); /////////////////////////// }////////////////////////////////////////////////////////////////////////////////////////// const posts = await db.Post.findAll({ where: { GpostId: req.params.id, }, include: [{ model: db.User, attributes: ['id', 'nickname'], },{ model: db.Image, },{ model: db.User, through: 'Like', as:'Likers', attributes:['id'], }], order: [['createdAt', 'DESC']], // DESC는 내림차순, ASC는 오름차순 }); res.json(posts); } catch (e) { console.error(e); next(e); } }); < post.js/ routes / back > // 게시물 올리기 route : http://localhost:3060/post/개발자 router.post('/:id', isLoggedIn, upload.none(), async (req, res, next) => { try { // 부모가되는 그룹포스트가있는지 ///////////////////////////////////////////// const gpost = await db.Gpost.findOne({ where: { id: req.params.id } }); if (!gpost) { return res.status(404).send('포스트가 존재하지 않습니다.????'); } /////////////////////////////////////////////////////////////////////////// const newPost = await db.Post.create({ content: req.body.content, UserId: req.user.id, GpostId: gpost.id, // 어떤 그룹에 속해있는지 }); await gpost.addPost(newPost.id); /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// if (req.body.image) { // 이미지 주소를 여러개 올리면 image: [주소1, 주소2] if (Array.isArray(req.body.image)) { const images = await Promise.all(req.body.image.map((image) => { return db.Image.create({ src: image }); })); await newPost.addImages(images); } else { // 이미지를 하나만 올리면 image: 주소1 const image = await db.Image.create({ src: req.body.image }); await newPost.addImage(image); } } const fullPost = await db.Post.findOne({ where: { id: newPost.id }, include: [{ model: db.User, attributes: ['id', 'nickname'], },{ model: db.Image, },{ model:db.User, as:"Likers", attributes:['id'], }], }); res.json(fullPost); } catch (e) { console.error(e); next(e); } }); <<<<<<<<<<<<<<<<<< post.js/ sagas / front >>>>>>>>>>>>>>>>>>>> // 게시물 올리기 function addPostAPI(postData){ // http://localhost:3060/post/10000 ///////////////////// return axios.post(`/post/${postData.gpostId}`, { content: postData.content },{ withCredentials: true ////////////////////////////////////////////////////////// }); //////////////////////////////////////////////////////////////////////////////// } function* addPost(action) { try { const result = yield call(addPostAPI, action.data); yield put({ type: ADD_POST_SUCCESS, data: { //////////////////////////////////////////////////////////////// gpostId: action.data.gpostId, content: result.data, },////////////////////////////////////////////////////////////////////// }); console.error(e); } catch (e) { yield put({ type: ADD_POST_FAILURE, error: e, }); } } function* watchAddPost(){ yield takeLatest(ADD_POST_REQUEST, addPost); } // 게시물 로드하기 function loadMainPostsAPI(gpostId) { // http://localhost:3060/post/10000 return axios.get(`/posts/${gpostId}`); ////////////////////////////////////////// } /////////////////////////////////////////////////////////////////////////////////// function* loadMainPosts(action) { try { const result = yield call(loadMainPostsAPI, action.data); yield put({ type: LOAD_MAIN_POSTS_SUCCESS, data: { gpostId: action.data, content: result.data, }, }); } catch (e) { yield put({ type: LOAD_MAIN_POSTS_FAILURE, error: e, }); } } function* watchLoadMainPosts() { yield takeLatest(LOAD_MAIN_POSTS_REQUEST, loadMainPosts); } < server.js / front> server.get('/post/:id', (req, res) => { // http://localhost:3060/post/1000000 return app.render(req, res, '/posted', { id: req.params.id }); }); < posted.js / pages / front > - server.js 에서 연결해주는 동적페이지 // 그룹: 동적페이지 const Posted = () => { . . . return ( <> <div className="wrap"> {/* GpostId와 그룹의 id가 같을경우에만 화면에 표시 */} {GroupPosts.map((val)=>{ var gid = window.location.href.split("/").reverse()[0]; if( gid == val.id){ return( <div> <GroupBox gpost={val} gimg={val.GImgs} /><UploadForm gpost={val} /> </div> ); } })} </div> </> ); }; Posted.getInitialProps = async (context) => { console.log('posted getInitialProps', context.query.title); }; export default Posted; < UploadForm.js / Component / front > - 게시물올리는 컴포넌트 onSubmitForm 함수부분 const onSubmitForm = useCallback((e) => { e.preventDefault(); if (!text || !text.trim()) { return alert('게시글을 작성하세요.'); } const formData = new FormData(); imagePaths.forEach((i) => { formData.append('image', i); }); formData.append('content', text); //////////////////////////////////////////////////// formData.append('GpostId', gpost.id); //////////////////// <- ////////////////////////// dispatch({ //////////////////////////////////////////////////// type: ADD_POST_REQUEST, data: formData, }); }, [text, imagePaths, gpost.id]); < post.js /reducers / front > // 게시물 불러오기 case LOAD_MAIN_POSTS_REQUEST: { return { ...state, mainPosts: [], }; } case LOAD_MAIN_POSTS_SUCCESS: { return { ...state, mainPosts: action.data, }; } case LOAD_MAIN_POSTS_FAILURE: { return { ...state, }; } < WorkBench > - GpostId 의 파란색부분은 워크벤치에서 임의로 넣어주었습니다. + 노드 백서버 오류메세지입니다
- 미해결React로 NodeBird SNS 만들기
typeError
https적용후 에러 입니다. 함수를 사용 못한다는데 ..
- 미해결React로 NodeBird SNS 만들기
댓글이 첫번째 포스트카드에만 붙습니다.
원인파악이 잘안되네요.. post.id가 카드를 생성해도 계속 1로만 있는것 같은데 이유를 잘 모르겠습니다. 아래 코드인데 한번 봐주실 수 있을까요.. 아니면 디버깅 방법이라도 알려주시면 감사하겠습니다. 선택한카드에 댓글버턴을 눌렀을때 선택한 카드를 콘솔에 찍는방법이 잘 안떠오릅니다. 콘솔에는 아래와 같은 에러가 뜹니다. Warning: Encountered two children with the same key, `[object Object]`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version. in Home (at _app.js:24) in div (created by Context.Consumer) in Col (at AppLayout.js:54) in div (created by Context.Consumer) in Row (at AppLayout.js:50) in AppLayout (at _app.js:23) in Provider (at _app.js:15) in NodeBird (created by withRedux(NodeBird)) in withRedux(NodeBird) in Container (created by AppContainer) in AppContainer ***** postcard.js ================== import React, { useState, useCallback, useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { ADD_COMMENT_REQUEST } from "../reducers/post"; import { Card, Button, Avatar, Input, Comment, List, Form } from "antd"; import { RetweetOutlined, HeartOutlined, MessageOutlined, EllipsisOutlined, } from "@ant-design/icons"; const PostCard = ({ post }) => { const [commentFormOpened, setCommentFormOpened] = useState(false); const [commentText, setCommentText] = useState(""); const { me } = useSelector((state) => state.user); const { isAddedComment, isAddingComment } = useSelector( (state) => state.post ); const dispatch = useDispatch(); useEffect(() => { console.log("effect"); setCommentText(""); }, [isAddedComment === true]); const onCommentToggle = useCallback(() => { setCommentFormOpened((prev) => !prev); }, []); const onChangeCommentText = useCallback((e) => { setCommentText(e.target.value); }, []); const onSubmitComment = useCallback(() => { if (!me) { return alert("Please Login First"); } console.log("submit"); console.log(post.id); return dispatch({ type: ADD_COMMENT_REQUEST, data: { postId: post.id } }); }, [me && me.id]); return ( <div> <Card key={+post.createdAt} hoverable style={{ width: 240, padding: 10, marginTop: 10 }} cover={post.img && <img alt={post} src={post.img} />} actions={[ <RetweetOutlined />, <HeartOutlined />, <MessageOutlined onClick={onCommentToggle} />, <EllipsisOutlined />, ]} extra={<Button>Delete</Button>} > <Card.Meta title={post.User.nickName} description={post.content} ></Card.Meta> </Card> {commentFormOpened && ( <React.Fragment> <Form onFinish={onSubmitComment}> <Form.Item> <Input.TextArea rows={4} value={commentText} onChange={onChangeCommentText} /> </Form.Item> <Button type="primary" htmlType="submit" loading={isAddingComment}> Reply </Button> </Form> <List header={`${post.Comments ? post.Comments.length : 0} 댓글`} itemLayout="horizontal" dataSource={post.Comments || []} renderItem={(item) => ( <li> <Comment author={item.User.nickName} avatar={<Avatar>{item.User.nickName[0]}</Avatar>} content={item.content} /> </li> )} /> </React.Fragment> )} </div> ); }; export default PostCard; ***** index.js================== import React from "react"; import Postform from "../components/postform"; import PostCard from "../components/postcard"; import { useSelector } from "react-redux"; const Home = () => { const { mainPosts } = useSelector((state) => state.post); const { isLogged } = useSelector((state) => state.user); return ( <React.Fragment> {isLogged && <Postform />} {mainPosts.map((v) => { return <PostCard key={v} post={v} />; })} </React.Fragment> ); }; export default Home; ***** sagas/post.js ================== import { delay, fork, all, takeLatest, put } from "redux-saga/effects"; import { ADD_POST_REQUEST, ADD_POST_SUCCESS, ADD_POST_FAILURE, ADD_COMMENT_REQUEST, ADD_COMMENT_SUCCESS, ADD_COMMENT_FAILURE, } from "../reducers/post"; // ACTION_API, ACTION_NAME, ACTION_WATCH are set function* addPostAPI() { // return axios.post('/post') } function* addPost() { try { yield delay(2000); yield put({ type: ADD_POST_SUCCESS }); } catch (e) { console.log(e); yield put({ type: ADD_POST_FAILURE, postErrorReason: e }); } } // add Comment function* addPostWatch() { yield takeLatest(ADD_POST_REQUEST, addPost); } function* addCommentAPI() { // return axios.post('/post') } function* addComment(action) { try { yield delay(2000); yield put({ type: ADD_COMMENT_SUCCESS, data: { postId: action.data.postId }, }); } catch (e) { console.log(e); yield put({ type: ADD_COMMENT_FAILURE, commentErrorReason: e }); } } function* addCommentWatch() { yield takeLatest(ADD_COMMENT_REQUEST, addComment); // dispatch할때 action값이 addComment로 넘어가는듯 } export default function* postSaga() { yield all([fork(addPostWatch), fork(addCommentWatch)]); } ***** reducer/post.js ================== 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 ADD_COMMENT_REQUEST = "ADD_COMMENT_REQUEST"; export const ADD_COMMENT_SUCCESS = "ADD_COMMENT_SUCCESS"; export const ADD_COMMENT_FAILURE = "ADD_COMMENT_FAILURE"; export const initialState = { mainPosts: [ { id: 1, User: { id: 1, nickName: "", }, content: "", img: "https://img.icons8.com/plasticine/2x/image.png", Comments: [], }, ], imagePaths: [], isAddingPost: false, isAddedPost: false, postErrorReason: "", isAddingComment: false, isAddedComment: false, commentErrorReason: "", }; const dummyPost = { id: 2, User: { id: 1, nickName: "dum cho", }, content: "dummy Post", Comments: [], img: "https://img.icons8.com/plasticine/2x/image.png", }; const dummyComment = { id: 1, User: { id: 1, nickName: "dum cho", }, Comments: "this is dummy", }; const reducer = (state = initialState, action) => { switch (action.type) { case ADD_POST_REQUEST: return { ...state, mainPost: action.data, isAddedPost: false, isAddingPost: true, }; case ADD_POST_SUCCESS: return { ...state, mainPosts: [dummyPost, ...state.mainPosts], isAddedPost: true, isAddingPost: false, }; case ADD_POST_FAILURE: return { ...state, mainPost: action.data, isAddedPost: false, isAddingPost: false, }; case ADD_COMMENT_REQUEST: return { ...state, isAddedComment: false, isAddingComment: true, }; case ADD_COMMENT_SUCCESS: { const postIndex = state.mainPosts.findIndex( (v) => v.id === action.data.postId ); // console.log(action.data.postId, postIndex); const post = state.mainPosts[postIndex]; const Comments = [...post.Comments, dummyComment]; const mainPosts = [...state.mainPosts]; mainPosts[postIndex] = { ...post, Comments }; return { ...state, mainPosts, isAddedComment: true, isAddingComment: false, }; } case ADD_COMMENT_FAILURE: return { ...state, mainPost: action.data, isAddedComment: false, commentErrorReason: false, }; default: return { ...state }; } }; export default reducer;
- 미해결React로 NodeBird SNS 만들기
db설정 질문
앞의 config.json을 설정하는 부분에서 질문이있습니다. password는 제 db의 비밀번호이고 database는 제 db안에 react-nodebird라는 db를 만들어 두어야 하나요??
- 미해결React로 NodeBird SNS 만들기
데이터베이스 다대다 관계 연결 질문입니다
await aaa.addfollowings(2)를 통해서 팔로우를 연결하려고 할때 마다 typeerror: aaa.addfollowings is not a function이라고 나와요.. 어떻게해야 할까요?
- 미해결React로 NodeBird SNS 만들기
dispatch router질문입니다
a쪽 컴포넌트는 const codeConfirm=useCallback(async()=>{ const codeDispatch=useCallback(async(resolve,reject)=>{ return await new Promise((resolve,reject)=>{ dispatch({ type:CODE_REQUEST, data:code }); resolve(); } ) },[code]) if(code===undefined){ alert('코드를 입력해주세요'); return; } await codeDispatch().then(()=>{ if(codeInfo){ router.push('/b'); } }) },[code]) 이렇게 짜보았고 b쪽은 useEffect(()=>{ if(!codeInfo){ console.log(codeInfo); alert('잘못 된 코드를 입력하였습니다'); router.push({pathname:'/a'}); } },[codeInfo]) 이런식으로 짜보았는데 b로 넘어갔다가 a로 다시넘어가는 현상이있습니다
- 미해결React로 NodeBird SNS 만들기
dispatch질문입니다.
a 라는 컴포넌트에서 b라는 컴포넌트로 넘어갈때 a에서 dispatch->통신->data 값을 받아서 그 data값이 있으면 b로넘어 갈수 있고 없으면 b로 못넘어가게 막고싶은데 이부분이 잘안됩니다... a화면에서 데이터값을 받아도 b화면 useEffect에서 data검사후 없으면 돌려보내는식으로 하고있는데 통신이 잘되어서 data값이 있음에도 useEffect에서 무조건 돌려 보내서 다른방법이 있나질문드립니다.
- 미해결React로 NodeBird SNS 만들기
댓글 삭제 화면 반영 문제
https://www.inflearn.com/questions/33101 댓글 삭제가 db에서는 반영이 되는데, 화면에는 반영이 바로 되지 않는 문제로 ㅠㅠ 질문 드립니다. <코드> <router> 여기서 궁금한 점이 하나 있는데, like와 unlike를 보면 addLiker, removeLiker로 삭제해주고 있는데 comment delete부분에 removeLiker을 넣으려면 post id를 찾은 후 removeComment를 넣어줘야 하는건지 그거에 대해 계속 시도중입니다 ㅠㅡㅠ <saga> data에 postId를 넣어 전달해줘야하나해서 넣은 부분이구요 <reducer> reducer 부분입니다 ㅠㅠ db에서는 삭제가 되는데, redux에서는 failure로 불러오고 있습니다. 아마 destroy로 삭제가 되는데 화면 반영은 안 되는 것 같습니다 router 부분이 어려워서 ㅠㅠ...! post id를 comment에 기반해서 where이나 include로 불러와줘야 하는것인지 ㅠㅠ... 아니면 다른 코드들에 오류가 있는건지 ㅠㅠ...! 부탁드립니다