묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
Next 14 강의
안녕하세요,슬랙 채널에서 Next 14 강의 업로드 예정이시라는 글을 봤습니다. 해당 강좌의 리뉴얼 버전이라고 보면 될까요? 차이점이 궁금합니다.감사합니다.
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
미리보기가 보이지 않습니다
//app.js app.use('/', express.static(path.join(__dirname, 'uploads'))); //PostForm.js import { Button, Form, Input } from 'antd'; import React, { useCallback, useEffect, useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; import useInput from '../hooks/useInput'; import { ADD_POST_REQUEST, REMOVE_IMAGE, UPLOAD_IMAGES_REQUEST, addPost, } from '../reducers/post'; const FormWrapper = styled(Form)` margin: 10px 0 20px; `; const ButtonStyle = styled(Button)` float: 'right'; `; const PostForm = () => { const { imagePaths, addPostLoading, addPostDone } = useSelector( (state) => state.post ); const dispatch = useDispatch(); const imageInput = useRef(); const [text, onChangeText, setText] = useInput(''); useEffect(() => { if (addPostDone) { setText(''); } }, [addPostDone]); const onSubmitForm = useCallback(() => { if (!text || !text.trim()) { return alert('게시글을 작성하세요.'); } const formData = new FormData(); imagePaths.forEach((p) => { formData.append('image', p); }); formData.append('content', text); return dispatch({ type: ADD_POST_REQUEST, data: formData, }); }, [text, imagePaths]); const onClickImageUpload = useCallback(() => { imageInput.current.click(); }, [imageInput.current]); const onChangeImages = useCallback((e) => { console.log('images', e.target.files); //배열모양을 띄는 객체 const imageFormData = new FormData(); [].forEach.call(e.target.files, (f) => { imageFormData.append('image', f); }); dispatch({ type: UPLOAD_IMAGES_REQUEST, data: imageFormData, }); }, []); const onRemoveImage = useCallback( (index) => () => { dispatch({ type: REMOVE_IMAGE, data: index, }); }, [] ); return ( <FormWrapper encType='multipart/form-data' onFinish={onSubmitForm}> <Input.TextArea value={text} onChange={onChangeText} maxLength={140} placeholder='어떤 신기한 일이 있었나요?' /> <div> <input onChange={onChangeImages} type='file' name='image' hidden multiple ref={imageInput} /> <Button onClick={onClickImageUpload}>이미지 업로드</Button> <ButtonStyle type='primary' htmlType='submit'> Twit </ButtonStyle> </div> <div> {imagePaths.map((item, i) => ( <div key={item} style={{ display: 'inline-block' }}> <img src={`http://localhost:3065/${item}`} style={{ width: '200px' }} alt={item} /> <div> <Button onClick={onRemoveImage(i)}>제거</Button> </div> </div> ))} </div> </FormWrapper> ); }; export default PostForm; //post.js const multer = require('multer'); const path = require('path'); const fs = require('fs'); const { Post, Image, Comment, User } = 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({ destination(req, file, done) { done(null, 'uploads'); }, //배포때는 s3로 , 개발에는 드라이브에 filename(req, file, done) { const ext = path.extname(file.originalname); //확장자 추출 const basename = path.basename(file.originalname, ext); done(null, basename + '_' + new Date().getTime() + ext); //이나당151817842.png }, }), limits: { fileSize: 20 * 1024 * 1024 }, //20MB }); router.post('/', isLoggedIn, upload.none(), async (req, res, next) => { // POST /post try { const post = await Post.create({ content: req.body.content, UserId: req.user.id, }); 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); } } console.log('POST', post); const fullPost = await Post.findOne({ where: 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( '/images', isLoggedIn, upload.array('image'), async (req, res, next) => { //POST /post/images try { console.log(req.files); res.json(req.files.map((v) => v.filename)); } catch (error) { console.error(error); next(error); } } ); 안녕하세요 제로초님! 질문이 있습니다.. 파일은 제대로 올라가서 uploads 폴더안에 있는데 화면에서 이미지를 가져오지 못하고있습니다.. 프론트-백 api통신도 잘 되는데, 왜 개발자도구-네트워크에서 이미지를 가져올 수 없는지 이유를 모르겠습니다 ㅠㅠ
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
await에 대해 약간 헷갈리게되버렸어요
수업에서 async await를 쓰게 되면,await 뒤쪽 함수가 실행 된 후, await를 보자마자 어? 오래걸리겟네? 하면서 스레드가 해당 async함수를 통째로 마이크로큐에 넣어버린다고 말씀하셨는데요.만약 await뒤의 함수가 Promise를 반환하게 되면, 해당 Promise를 반환하는 함수가 먼저 큐에 쌓이고, 그 뒤에 async함수가 들어가서 pipo구조에 따라, promise가 반환된 후 async함수가 실행되면서 기다리는것처럼 보인다고 말해주셨습니다. 근데... 이 말 대로라면, await 함수 뒤에 굳이 Promise가 올 필요가 있나요? XMLHttpRequest()가 오더라도, 콜스택에서 해당요청이 실행된 후, 결과값을 가진 상태에서 마이크로큐로 들어가니까, 똑같이 await가 되는게 아닌지요? 분명 순차적으로 수업을 들으면서 다 이해햇다고 생각햇는데갑자기 헷갈립니다.
-
해결됨Next.js 시작하기(feat. 지도 서비스 개발)
서버사이드 렌더링을 할 때, 서버는 어디에 있는 건가요?
선생님, 안녕하세요. 너무 기초적인 질문일 수 있지만, 갑자기 궁금해져서 질문드립니다. 서버사이드 렌더링의 경우, 서버에서 pre-render된 코드를 만들어서 보내주고, 클라이언트에서 hydrate를 해서 페이지를 만든다고 알고 있습니다. 클라이언트 사이드 렌더링의 경우는 html코드와 js코드를 함께 보내서, 클라이언트에서 페이지를 만들구요. 서버사이드 렌더링을 할 때, pre-render된 코드를 만드는 서버는 각 클라이언트들의 컴퓨팅 자원을 사용하는 건지(클라이언트의 컴퓨터에서 만드는 건지), 아니면 배포하는 중앙(?)서버(aws ec2 또는 이 강의에서 처럼 vercel)의 컴퓨팅 자원을 사용하는 건지(서버에서 만드는 건지) 궁금합니다. 클라이언트 측에서 다 계산을 한다고 하면, 중앙(?)서버의 부담이 적을테지만, 중앙(?)서버에서 한다고 하면, 부담이 갈 수 있을 것 같아서요. 최근 next.js 14버전이 되면서 디비와 직접 통신하는 등 기능이 많이 생겼는데, 이 통신하는 등의 역할은 client side가 아닌 server side에서만 가능하더라구요. 그래서 server side라는 게 중앙서버 하나에만 있다면, 계산이 오래걸린다거나 트래픽이 늘어나거나 한다면 다른 사용자들에게도 영향을 끼치지 않을까 궁금했습니다.(자동 확장이 되지 않을때) 또, 이런식으로 간다면 따로 백엔드 서버가 필요없게 될 수도 있겠다라고도 생각해봤는데, 어떻게 보고계시는지도 궁금합니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
구글 콘솔로그 오류창이 계속 떠요
구글 웹에서 콘솔창을 켜면 계속 이 오류 화면이 뜨는데, 처음에는 무시하고 진행했는데 몇 달간 계속 뜨고 타이머 실습할 때 조금 끊기는 것 같기도 해요ㅜㅠ GPT에 물어보니까 권한이 적절치 않다고 하는데 어떻게 해결할 수 있는 건가요??ㅜㅜ
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
[공유] Next.js 12버전 redirect
import { useRouter } from 'next/router'; const Profile = () => { ... const router = useRouter(); if (!me) { router.push('/'); return null; } ... }이런식으로 하면 잘 동작해요~
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
체크박스 클릭 구현 함수에 대해서 질문드립니다.
input checkbox 에서onChange={() => this.handleCompleChange(data.id)}함수를 실행하게끔하는데 () => 는 왜들어가는걸까요? 예를들어 같은 방식의 함수중에 onChange={this.handleChange} 함수의경우엔 () => 가 없더라구요. 구현 부분은 똑같이 함수이름 = (파라미터) => {} 로 구현되어 있습니다.
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
영화 나열을 위한 Row 컴포넌트 생성하기
8분 47초 까지 따라했는데, 오류가 뜹니다.import React, { useEffect } from 'react' import axios from '../api/axios' export default function Row({ isLargeLow, title, id, fetchUrl }) { useEffect (() => { fetchMovieData(); }, []); const fetchMovieData = async () => { const request = await axios.get(fetchUrl); console.log('request', request); }; return ( <div> </div> ) } 터미널에서는 아래와 같은 오류가 뜨고,WARNING in ./src/components/Banner.css (./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[1].oneOf[5].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[1].oneOf[5].use[2]!./node_modules/source-map-loader/dist/cjs.js!./src/components/Banner.css) Module Warning (from ./node_modules/postcss-loader/dist/cjs.js): Warning (75:5) autoprefixer: start value has mixed support, consider using flex-start instead WARNING in [eslint] src/components/Row.js Line 7:8: React Hook useEffect has a missing dependency: 'fetchMovieData'. Either include it or remove the dependency array react-hooks/exhaustive-deps webpack compiled with 2 warnings 아래는 크롬에서 뜨는 오류입니다.Uncaught runtime errors: × ERROR Cannot read properties of undefined (reading 'fetchNetflixOriginals') TypeError: Cannot read properties of undefined (reading 'fetchNetflixOriginals') at App (http://localhost:3000/static/js/bundle.js:46:61) at renderWithHooks (http://localhost:3000/static/js/bundle.js:20698:22) at mountIndeterminateComponent (http://localhost:3000/static/js/bundle.js:23984:17) at beginWork (http://localhost:3000/static/js/bundle.js:25280:20) at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:10290:18) at Object.invokeGuardedCallbackDev (http://localhost:3000/static/js/bundle.js:10334:20) at invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:10391:35) at beginWork$1 (http://localhost:3000/static/js/bundle.js:30265:11) at performUnitOfWork (http://localhost:3000/static/js/bundle.js:29512:16) at workLoopSync (http://localhost:3000/static/js/bundle.js:29435:9) ERROR Cannot read properties of undefined (reading 'fetchNetflixOriginals') TypeError: Cannot read properties of undefined (reading 'fetchNetflixOriginals') at App (http://localhost:3000/static/js/bundle.js:46:61) at renderWithHooks (http://localhost:3000/static/js/bundle.js:20698:22) at mountIndeterminateComponent (http://localhost:3000/static/js/bundle.js:23984:17) at beginWork (http://localhost:3000/static/js/bundle.js:25280:20) at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:10290:18) at Object.invokeGuardedCallbackDev (http://localhost:3000/static/js/bundle.js:10334:20) at invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:10391:35) at beginWork$1 (http://localhost:3000/static/js/bundle.js:30265:11) at performUnitOfWork (http://localhost:3000/static/js/bundle.js:29512:16) at workLoopSync (http://localhost:3000/static/js/bundle.js:29435:9) ERROR Cannot read properties of undefined (reading 'fetchNetflixOriginals') TypeError: Cannot read properties of undefined (reading 'fetchNetflixOriginals') at App (http://localhost:3000/static/js/bundle.js:46:61) at renderWithHooks (http://localhost:3000/static/js/bundle.js:20698:22) at mountIndeterminateComponent (http://localhost:3000/static/js/bundle.js:23984:17) at beginWork (http://localhost:3000/static/js/bundle.js:25280:20) at beginWork$1 (http://localhost:3000/static/js/bundle.js:30243:18) at performUnitOfWork (http://localhost:3000/static/js/bundle.js:29512:16) at workLoopSync (http://localhost:3000/static/js/bundle.js:29435:9) at renderRootSync (http://localhost:3000/static/js/bundle.js:29408:11) at recoverFromConcurrentError (http://localhost:3000/static/js/bundle.js:28900:24) at performConcurrentWorkOnRoot (http://localhost:3000/static/js/bundle.js:28812:26)
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
섹션 13에 타입스크립트 실행관련
타입스크립트 본수업은 문제없이 진행했는데 freeboard 부분을 진행하다가 api 관련 타입스크립트 설치 과정을 하는데 에러가 보입니다.. 이부분 혹시 뭐때문에 발생하는건지 확인 해주실 수 있으실까요ㅠㅠ
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
모달 창 외부 클릭 시 모달 닫게 만드는 Custom Hooks 생성 이 강의 오타부분
모달 창 외부 클릭 시 모달 닫게 만드는 Custom Hooks 생성 이 강의에서 useOnClickOutside custom hooks부분에서 event listener해제하는 부분이 addEventListener로 잘못되어 있내요
-
해결됨손에 익는 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로 NodeBird SNS 만들기
[공유] input 속성에 hidden 이 적용 안될 때
<input type='file' multiple style={{ display: 'none' }} />display: 'none'으로 줘보세요!
-
해결됨손에 익는 Next.js - 공식 문서 훑어보기
Revalidate 부분 질문
질문 가이드 📖 안녕하세요.강의 중 날씨 데이터 재검증하기 부분에서 코드를 강사님 코드를 따라하다가시간 api fetch 부분에서 아래와 같은 에러가 발생이 되어서 질문 드립니다.강사님 코드를 깃에서 받아서 IDE (vscode, webstorm) 열어봐도 똑같은 현상이 보입니다.혹시 이런 부분에 대해서 알고 계신 내용이 있으시다면 답변주시면 감사드리겠습니다. 참고로 노드 버전은 20.9.0입니다!
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
회원가입 누르면 404에러가 뜹니다 ;-;
안녕하세요 ;-;회원가입 누르니 404에러가 뜹니다..완성 코드랑 비교해서 봐도 똑같은데 어떤 문제인지 모르겠스빈다... next.js가 13이긴 합니다만 ;-; 그 이유 일까요?.. 어디를 살펴보면 될까요?;-;
-
해결됨[리뉴얼] 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 관련 이미지는 적용한 적이 없습니다!)에러를 번역해보니 다음과 같았습니다.
-
미해결[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
이벤트 위임 관련 질문드려요!
안녕하세요!이벤트 위임이란 이벤트 버블링을 이용하여 상위 태그에 이벤트 핸들러를 할당하여 하위 태그에서 중복되는 이벤트들을 없앨 수 있다. 이 과정에서 원치 않은 이벤트 버블링를 막기 위해서는 event.stopPropagation() 함수를 사용해야 한다. 라고 이해했습니다.이벤트 위임 관련해서 구글링 해보니, 구현 방식에 있어서 자바스크립트와 리액트에서 차이가 있다고 보았는데 자료들이 부정확하고 이해하기 어려워서 질문드립니다. 리액트와 자바스크립트에서 이벤트 버블링 구현시 어떤 차이가 있으며 그 이유와 원리에 대해 설명 부탁드립니다..!항상 좋은 강의 감사드립니다이벤트 위임 관련 아래 링크 첨부합니다.https://github.com/facebook/react/issues/13635https://github.com/facebook/react/issues/13625
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
이벤트 핸들러 관련 질문드려요!
안녕하세요! 이벤트처리 함수 관련해서 질문드립니다.현재는 event를 넘겨서 처리하고 있다보니 currentTaget이니 target이니 신경 쓸 것이 많은데, <div onClick(() => onClickAlert(el.writer)} > 이렇게 바로 id의 값을 바인딩시켜줘도 되지 않나요?혹시 수업에서와 같이 <div id={el.writer} onClick={onClickAlert}> id 속성을 부여하고 이를 onClickAlert에서 event를 받아서 처리해야만 하는 상황이나 위와 같이 했을 때의 이점이 있는지 궁금합니다!항상 좋은 강의 감사드려요!
-
해결됨손에 익는 Next.js - 공식 문서 훑어보기
서버 컴포넌트 관련 질문입니다!
SSR 방식에 서버 컴포넌트와 클라이언트 컴포넌트를 둘 다 적절히 사용하는 것인가요??서버 컴포넌트는 데이터 페칭, 보안, 캐싱, JS 번들크기 감소와 같은 장점이 있고 event와 hook을 사용하지 못한다는 특징도 이야기해주셨는데, 그렇다면 데이터를 받아서(페칭해서) 클라이언트 컴포넌트에 데이터를 뿌려주는 느낌으로 조합해서 사용하는 건가요??서버컴포넌트는 event를 사용하지 않으므로, TTI를 개선하기 위해 나온 개념은 아닌거죠???