묻고 답해요
161만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
[List 컴포넌트 생성하기] props 관련질문드립니다.
안녕하세요.기본적인 사항을 잘 몰라서 질의드립니다. props 를 내려주면서, data.id => id 형태로 수정을 해주는데요.함수 부분은 수정을 하지 않고 return 이하의 변수만 수정을 하는데 .. 이런 개념을 알려면 js 를 공부를 더 해야 할까요?? ㅡㅡ;
-
해결됨손에 익는 Next.js - 공식 문서 훑어보기
비동기 호출 관련 질문있습니다!
혹시 서버 컴포넌트에서만 비동기 호출이 가능한건가요??그렇다면 서버 컴포넌트가 컴포넌트를 서버 내에서 미리 만들어 둘 때, 비동기 호출을 통해 데이터를 가져와서 이 값을 미리 가져와서 컴포넌트를 만드는 건가요??그리고 만약 그렇다면 왜 서버 컴포넌트에서만 비동기 호출이 가능하도록 만드신 건지 의도를 아시고 계신지 궁금합니다! (단순히 서버 컴포넌트의 장점 때문인건가요??)그리고 강의의 진행은 SSR을 사용한다는 가정하에 진행해주셨던 게 맞나요?? (SSG도 동일한 건가요?)
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
카카오맵 이 출력이 안되요
window.kakao에 underfined로 나와요...
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
retweet 관련 질문이 있습니다.
다름이 아니라 리트윗빼고는 문제가 없습니다.하지만 리트윗을 하게 되면 데이터베이스에 userid가 null로 들어가면서 게시글을 불러올때 userid가 없기때문에 오류가 나는 것으로 보입니다... 해결해보려고 노력하는 중입니다만 어디가 문제인지 잘 모르겠습니다.const express = require("express"); const multer = require("multer"); const path = require("path"); const fs = require("fs"); const { Post, Image, Comment, User, Hashtag } = require("../models"); const { isLoggedIn } = require("./middlewares"); const router = express.Router(); try { fs.accessSync("uploads"); } catch (error) { console.log("uploads폴더가 없으므로 생성합니다."); fs.mkdirSync("uploads"); } const upload = multer({ storage: multer.diskStorage({ //어디에 저장할지 diskStorage => 하드디스크에 저장 destination(req, file, done) { done(null, "uploads"); }, filename(req, file, done) { // 제로초.png const ext = path.extname(file.originalname); // 확장자 추출(.png) const basename = path.basename(file.originalname, ext); // 제로초 done(null, basename + "_" + new Date().getTime() + ext); // 제로초15184712891.png }, }), limits: { fileSize: 20 * 1024 * 1024 }, // 20MB }); router.post("/", isLoggedIn, upload.none(), async (req, res, next) => { // 보기에는 "/"로 되어있지만 실제로는 "/post"로 되어있다. try { const hashtags = req.body.content.match(/#[^\s#]+/g); //hashtag 정규식 const post = await Post.create({ content: req.body.content, UserId: req.user.id, }); if (hashtags) { const result = await Promise.all( hashtags.map( (tag) => Hashtag.findOrCreate({ //있으면 가져오고 없으면 추가해라 where: { name: tag.slice(1).toLowerCase() }, }) //[[노드, true], [리액트, true]] 이런식으로 나옴 //slice는 글자만 떼기 위해 ex ) #react인 경우 react만 꺼냄 ) ); await post.addHashtags(result.map((v) => v[0])); //위에 같은 형식이기 때문에 0번째만 꺼내야함 } if (req.body.image) { if (Array.isArray(req.body.image)) { //여러개의 이미지를 올린 경우 const images = await Promise.all( req.body.image.map((image) => Image.create({ src: image })) ); await post.addImages(images); } else { const image = await Image.create({ src: req.body.image }); await post.addImages(image); } } const fullPost = await Post.findOne({ where: { id: post.id }, include: [ { model: Image, }, { model: Comment, include: [ { model: User, //댓글 작성자 attributes: ["id", "nickname"], }, ], }, { model: User, //게시글 작성자 attributes: ["id", "nickname"], }, { model: User, //좋아요 누른 사람 as: "Likers", attributes: ["id"], }, ], }); res.status(201).json(fullPost); //다시 프론트로 돌려주기 } catch (error) { console.error(error); next(error); } }); router.post("/:postId/comment", isLoggedIn, async (req, res, next) => { //:postId는 동적으로 바뀐다. //POST /post/comment // 보기에는 "/"로 되어있지만 실제로는 "/post"로 되어있다. try { const post = await Post.findOne({ //이 게시물이 진짜 있는지. where: { id: req.params.postId }, }); if (!post) { return res.status(403).send("존재하지 않는 게시글입니다."); } const comment = await Comment.create({ content: req.body.content, PostId: parseInt(req.params.postId, 10), //문자열로 넘어가기 때문에 int형으로 바꿔줘야한다. UserId: req.user.id, }); const fullComment = await Comment.findOne({ where: { id: comment.id }, include: [ { model: User, attributes: ["id", "nickname"], }, ], }); res.status(201).json(fullComment); } catch (error) { console.error(error); next(error); } }); router.patch("/:postId/like", isLoggedIn, async (req, res, next) => { //PATCH /post/1/like\ try { const post = await Post.findOne({ where: { id: req.params.postId } }); if (!post) { return res.status(403).send("게시글이 존재하지 않습니다."); } await post.addLikers(req.user.id); res.json({ PostId: post.id, UserId: req.user.id }); } catch (error) { console.error(error); next(error); } }); router.delete("/:postId/like", isLoggedIn, async (req, res, next) => { //DELETE /post/1/like try { const post = await Post.findOne({ where: { id: req.params.postId } }); if (!post) { return res.status(403).send("게시글이 존재하지 않습니다."); } await post.removeLikers(req.user.id); res.json({ PostId: post.id, UserId: req.user.id }); } catch (error) { console.error(error); next(error); } }); router.delete("/:postId", isLoggedIn, async (req, res, next) => { // DELETE /post/10 try { await Post.destroy({ where: { id: req.params.postId, UserId: req.user.id, }, }); res.status(200).json({ PostId: parseInt(req.params.postId, 10) }); } catch (error) { console.error(error); next(error); } }); router.post( "/images", isLoggedIn, upload.array("image"), //PostForm.js에서input에 올린 이미지가 배열로 들어감 (이미지를 여러장 올릴 수 있게 하기 위해서) async (req, res, next) => { // POST /post/images/ //이곳은 이미지 업로드 후 실행되는 부분, 업로드는 위에 upload에서 이미 다 올라감 console.log(req.files); res.json(req.files.map((v) => v.filename)); //프론트로 보내줌 } ); router.post("/:postId/retweet", isLoggedIn, async (req, res, next) => { // POST /post/1/retweet try { const post = await Post.findOne({ where: { id: req.params.postId }, include: [ { model: Post, as: "Retweet", }, ], }); if (!post) { return res.status(403).send("존재하지 않는 게시글입니다."); } if ( req.user.id === post.UserId || (post.Retweet && post.Retweet.UserId === req.user.id) ) { return res.status(403).send("자신의 글은 리트윗할 수 없습니다."); } const retweetTargetId = post.RetweetId || post.id; const exPost = await Post.findOne({ where: { UserId: req.user.id, RetweetId: retweetTargetId, }, }); if (exPost) { return res.status(403).send("이미 리트윗했습니다."); } const retweet = await Post.create({ UserId: req.user.id, RetweetId: retweetTargetId, content: "retweet", }); const retweetWithPrevPost = await Post.findOne({ where: { id: retweet.id }, include: [ { model: Post, as: "Retweet", include: [ { model: User, attributes: ["id", "nickname"], }, { model: Image, }, ], }, { model: User, attributes: ["id", "nickname"], }, { model: Image, }, { model: Comment, include: [ { model: User, attributes: ["id", "nickname"], }, ], }, ], }); res.status(201).json(retweetWithPrevPost); } catch (error) { console.error(error); next(error); } }); module.exports = router; //node에서는 import와 export defau lt를 사용하지 않고 require를 사용한다. //리트윗 case RETWEET_REQUEST: draft.retweetDone = false; draft.retweetLoading = true; 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; default: break; } }); export default reducer;//리트윗 function retweetAPI(data) { return axios.post(`/post/${data}/retweet`); //data는 formdata다 } 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({ type: RETWEET_FAILURE, error: err.response.data }); } }
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
setData(() => [newItem, ...data]) 동작 순서 질문입니다.
안녕하세요~ 강의 잘 보고 있습니다.setData([newItem, ...data]) 대신에 setData(() => [newItem, ...data])를 사용하는 이유가 useCallback이 완료된 후에 setState에서 () => [newItem, ...data] 를 호출 후 사용돼서 최신 데이터도 업데이트가 되고, 메모이제이션도 가능하게 된건가요?감사합니다.
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 챗봇 사이트 만들기
npm start 하고 throw e 이부분에서 에러가 뜨네요
npm start 하고 throw e 이부분에서 에러가 뜨네요..해결방법이 있을까요?
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
이 강의의 코드는 프로그래밍 패러다임 중 어떤 것이라 볼 수 있나요?
절차형, 객체지향, 함수형 셋 중 어떤 것이라 볼 수 있나요?
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
[공유] input 속성에 hidden 이 적용 안될 때
<input type='file' multiple style={{ display: 'none' }} />display: 'none'으로 줘보세요!
-
해결됨손에 익는 Next.js - 공식 문서 훑어보기
Revalidate 부분 질문
질문 가이드 📖 안녕하세요.강의 중 날씨 데이터 재검증하기 부분에서 코드를 강사님 코드를 따라하다가시간 api fetch 부분에서 아래와 같은 에러가 발생이 되어서 질문 드립니다.강사님 코드를 깃에서 받아서 IDE (vscode, webstorm) 열어봐도 똑같은 현상이 보입니다.혹시 이런 부분에 대해서 알고 계신 내용이 있으시다면 답변주시면 감사드리겠습니다. 참고로 노드 버전은 20.9.0입니다!
-
미해결웹 게임을 만들며 배우는 React
콘솔창에 wds 무한루프가 발생중입니다.
npm run dev를 실행하고 브라우저의 콘솔창을 보면 wds 무한루프가 발생하고 있습니다. 구글링을 해도 무슨문제인지 알 수 가 없어서 질문남깁니다! 혹시 뭐가 문제인지 알수있을까요?
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
회원가입 누르면 404에러가 뜹니다 ;-;
안녕하세요 ;-;회원가입 누르니 404에러가 뜹니다..완성 코드랑 비교해서 봐도 똑같은데 어떤 문제인지 모르겠스빈다... next.js가 13이긴 합니다만 ;-; 그 이유 일까요?.. 어디를 살펴보면 될까요?;-;
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
DataItem 컴포넌트 질문 있습니다.
안녕하세요, 강의 잘 보고 있습니다.DataItem 컴포넌트를 생성하고 이용하는 방법에 질문 두가지가 있습니다. (질문 1) DataItem을 자바스크립트 객체로 생성하는 방법과 jsx 컴포넌트로 생성하는 방법의 차이가 궁금합니다. jsx 컴포넌트를 이용할 때는 key값을 줄 수 있는것은 아는데요, 그 외의 차이점은 없는 것 같습니다. jsx 대신 DataItem 객체를 생성해서 사용해도 되나요?a. map에서 자바스크립트 객체로 생성하는 방법<div>{diaryList.map(i => DiaryItem(i)}<div> b. jsx의 컴포넌트로 생성하는 방법<div>{diaryList.map(i => <DiaryItem {...i}/>}<div> (질문 2) DataItem에 props를 넘겨주는 방법에 대한 질문입니다. props에 {...i} 처럼 전개연산자를 이용하여 한번에 여러 값을 전달해주고 있는데요, 그냥 i를 전달해주어도 되지 않나요? 전개연산자를 이용하여 넘겨주는 이유가 리액트 문법 때문인지, 새 객체로 복사해서 넘겨주고 싶기 때문인건지, 혹은 다른 이유때문인지 질문 드립니다.<div>{diaryList.map(i => <DiaryItem {...i} />}</div>
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
faker 적용 후 이미지가 깨지는 오류, 게시글 이미지 클릭 시 이미지 확대 화면의 fill-rule(fillRule) 에러에 관한 질문
안녕하세요! React로 NodeBird SNS 만들기섹션3 Redux-saga 연동까지 모두 수강한 수강생입니다!사전에 제로초님 강의와 트위터 클론 깃허브를 확인하였고, 구글링 및 에러를 번역했습니다!항상 강의 잘 보고 있습니다! 제로초님 항상 감사합니다!(1) 아래 질문 글과 동일하게 faker 이미지가 깨지는 현상이 발생했습니다!https://www.inflearn.com/course/lecture?courseSlug=%EB%85%B8%EB%93%9C%EB%B2%84%EB%93%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A6%AC%EB%89%B4%EC%96%BC&unitId=48831&category=questionDetail&tab=community&q=451330lorempixel 사이트 고장이 원인이라 다른 대체 사이트(placeimg)를 찾아봤지만 해결이 되지 않아 질문 올립니다!옆의 에러를 번역해보니 사이트 자체에서 이미지 찾을 수 없다고 합니다!+++(2) Warning: Invalid DOM property fill-rule. Did you mean fillRule? 에러게시글 이미지 클릭 시 콘솔에 fill-rule 에러가 발생합니다!faker 적용 전, 게시글 더미이미지가 있었을 때도 똑같은 에러가 발생하였습니다!더미이미지 삭제 전에도 진행 자체에 문제가 없고, 콘솔에 오류만 출력 되었는데 그냥 넘어가도 되는 에러인지 궁금합니다!(svg 관련 이미지는 적용한 적이 없습니다!)에러를 번역해보니 다음과 같았습니다.
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
[TailWindCss]Install Tailwind CSS with Create React App 관련문의드립니다.
안녕하세요. 초급이라 여러모로 잘 몰라서 질의드립니다. 강의화면상에서는 경고메시지가 없고, tailwindcss 설치시 명령어가 npm install -D tailwindcss postcss autoprefixer 로 tailwindcss 외에 postcss autoprefixer 의 두가지가 더 있는데요 . [강의화면]현재 tailwindcss 사이트에서 install 화면은 tailwindcss 하나만 인스톨하도록 가이드가 되어 있고react 보다는 다른 툴(?)을 사용하라는 경고가 있는데요. 가이드를 무시하고 일단 강의 내용대로 npm install -D tailwindcss postcss autoprefixer로 인스톨하니, postcss, autoprefixer 가 인스톨 된 것 같긴한데 이렇게 인스톨하더라도 혹시 react app 사용상에 뭔가 제약사항이 있는 건가요?? "devDependencies": { "autoprefixer": "^10.4.16", "postcss": "^8.4.31", "tailwindcss": "^3.3.5"
-
해결됨웹 게임을 만들며 배우는 React에 TypeScript 적용하기
createRoot
import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import GuGuDan from './GuGuDan'; ReactDOM.createRoot(document.querySelector('#root')!).render(<GuGuDan />);https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43848createRoot 에러 나길래 이슈에서 해결 방법 찾아서 공유드립니다!
-
미해결iOS/Android 앱 개발을 위한 실전 React Native - Basic
리액트 네이티브에서 안드로이드 실행
(node:13548) Warning: Accessing non-existent property 'padLevels' of module exports inside circular dependency(Use `node --trace-warnings ...` to show where the warning was created)error Android project not found. Are you sure this is a React Native project? If your Android files are located in a non-standard location (e.g. not inside 'android' folder), consider setting `project.android.sourceDir` option to point to a new location. 이거 무슨 에러인가요ㅠㅠ
-
미해결처음 만난 리액트(React)
node.js 설치
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.node.js 설치를 완료했는데 버전이 안나오는데 왜 그런건가요?
-
해결됨Slack 클론 코딩[실시간 채팅 with React]
unread Count 같은 경우 실무에선는 DB에 마지막 일자를 기록하나요?
강의에서 localStorage 를 이용하여 접속시간 or 마지막 불러온 일자를 저장하고그 local 값을 unreads 에 after 파람으로 전송하여 읽지않은 메시지를 카운트 햇는데해당 방식은 다른 아이디로 로그인 시 같은 local 데이터를 활용하기도 하고 다른 기기에 접속시 해당값은 날라가게 될텐데 이는 에러사항으로 이어질 것으로 예상됩니다.마지막 일자를 활용하게 된다면 이 값은 db에 저장되야 할걸로 생각이 되는데 맞을까요?
-
미해결따라하며 배우는 리액트, 파이어베이스 - 채팅 어플리케이션 만들기[2023.12 리뉴얼]
회원가입 유효성 부분 페이지 안뜨는 이유 좀요....
import React ,{useRef}from 'react' import { Link } from 'react-router-dom' import {useForm} from 'react-hook-form' function RegisterPage() { const {register,watch,errors} = useForm() const password = useRef(); console.log(watch("email")) return ( <div className='auth-wrapper'> <div style={{textAlign:'center'}}> <h3>Register</h3> </div> <form> <label>Email</label> <input name="email" type='email' // ref={register({ required: true, pattern: /^[0-9a-zA-Z]([-_._]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_._]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i })} /> {/* {errors.email && <p>This field is required</p>} */} <label>Name</label> <input name="name" // ref={register({ required: true, maxLength: 10 })} /> {/* {errors.name && errors.name.type ==="requirerd" && <p>This field is required</p>} {errors.name && errors.name.type ==="maxLength" && <p>This input exceed maximum length</p>} */} <label>Password</label> <input name="password" type='password' // ref={register({required: true, minLength:6})} /> {/* {errors.password &&errors.password && errors.password.type ==="required" && <p>This name field is required</p>} {errors.password &&errors.password && errors.password.type ==="minLength" && <p>비밀번호 자리가 6자리 이상이어야 합니다.</p>} */} <label>Password Confirm</label> <input name="Password Confirm" type='password' // ref={register({ // required:true, // validate:(value)=> // value === password.current // })} /> {/* {errors.password_confirm && errors.password_confirm.type ==="required" && <p>This password confirm field is required</p>} {errors.password_confirm && errors.password_confirm.type ==="validate" && <p>This passwords do not match</p>} */} <input type="submit" /> <Link style={{color:'gray',textDecoration:'none'}}to="/login" >이미 아이디가 있다면</Link> </form> </div> ) } export default RegisterPage 이렇게 저 부분을 주석처리하면 회원가입 페이지가 나오는데 주석처리를 해제하면 회원가입 페이지가 안떠요...
-
해결됨Slack 클론 코딩[실시간 채팅 with React]
내부디비를 세부적으로 쓰고싶은데...
sleact 서비스에 내부스토리지 (web스토리지,indexedDB) 를 좀더 체계적으로 써야될것같은데zustand 같은 상태관리 라이브러리에 내부스토리지를 연결하는게 좋을까요? 아니면 swr 같은데다 연결하는게 좋을까요? 아니면 내부스토리 접근하는 코드 따로 빼놓고 데이터 가져와서 state 에 관리하는게 나을까요?