묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
src참조 오류 관련 질문드리겠습니다.
ADD_POSTING_SEUCCESS후에 다음과 같이 정상적으로 post가 등록됬습니다.근데 아래와 같이 클라이언트에서 포스트의 이미지 주소를 참조하지 못하고 있다고 에러가 발생해서 질문드립니다.express static에서 문제가 발생한것같은데 혹시 해당 오류 원인에 대해서 알 수 있을까요?postcard.js const PostCard = ({ post }) => { const dispatch = useDispatch(); const id = useSelector((state) => state.user.me && state.user.me.id); const liked = post.Likers.find((v) => v.id === id); return ( <article> <CardWrapper bodyStyle={{height: '120px', overflow: 'hidden'}} hoverable cover={ <CardImageWrapper> <ImageWrapper alt="post image" src={`http://localhost3065/${post.Images[0].src}`} onClick={showPostModal} /> </CardImageWrapper> } : : export default PostCard;postingform.jsimport React, { useCallback } from 'react'; import { Button, Form, Input, Upload } from 'antd'; import { UploadOutlined } from '@ant-design/icons'; import { useDispatch, useSelector } from 'react-redux'; import Router from 'next/router'; import { PostingFormWrapper, FormWrapper, FormHeader, HeaderText, HeaderBtn, HeaderDiviver, ImageUploaderWrapper, ContentFormWrapper, TagsInputWrapper } from './styles'; import { ADD_POST_REQUEST, UPLOAD_IMAGES_REQUEST } from '../../reducers/post'; const PostingForm = () => { const { imagePaths, addPostLoading } = useSelector((state) => state.post); const dispatch = useDispatch(); const onSubmitForm = useCallback((value) => { console.log(value); dispatch({ type: ADD_POST_REQUEST, data: { imagePaths, content: value, } }) }, [imagePaths]); const normFile = useCallback((e) => { console.log(`normFile : ${e}`); if (Array.isArray(e)) { return e; } return e?.fileList; }, []); const onChangeImages = useCallback((e) => { console.log(`onchange : ${e}`); const imageFormData = new FormData(); e.fileList.forEach((f) => { imageFormData.append('image', f.originFileObj); }); dispatch({ type: UPLOAD_IMAGES_REQUEST, data: imageFormData, }); }, []); // const onRemoveImages = useCallback((e) => { // console.log(`onRemove : ${e.name}`); // }, []); const onBeforeUpload = useCallback((file, fileList) => { // Return False So That Antd Doesn't Upload The Picture Right Away return false }, []); return ( <section> <PostingFormWrapper name="posting" onFinish={onSubmitForm} scrollToFirstError encType='multipart/form-data' > <FormWrapper style={{marginBottom: '1em'}}> <FormHeader> <HeaderText>Post Writing</HeaderText> <div> <HeaderBtn type='primary' size='large' htmlType="submit" loading={addPostLoading} > 등록 </HeaderBtn> <Button size='large'>취소</Button> </div> </FormHeader> <HeaderDiviver /> </FormWrapper> <FormWrapper name="title" rules={[ { type: 'text', }, { required: true, message: '포스팅 제목을 입력하세요.', }, ]} hasFeedback > <Input placeholder='제목을 입력해 주세요.' allowClear="true" size='large' /> </FormWrapper> <FormWrapper name="desc" rules={[ { type: 'text', }, ]} > <Input placeholder='포스팅의 간략한 설명을 입력해 주세요.' allowClear="true" size='large' /> </FormWrapper> <ImageUploaderWrapper name="images" rules={[ { required: true, message: '조리사진을 첨부하세요.', }, ]} valuePropName="fileList" getValueFromEvent={normFile} > {/* action: 파일을 업로드할 실제 URL -> localhost3065/images */} <Upload.Dragger name="image" multiple // action="http://localhost:3065" listType="picture" onChange={onChangeImages} // onRemove={onRemoveImages} beforeUpload={onBeforeUpload} > <p style={{marginBottom: '0.5em'}}>Drag files here OR</p> <Button type='primary' size='large' icon={<UploadOutlined />}>Upload</Button> </Upload.Dragger> </ImageUploaderWrapper> <ContentFormWrapper name="ingredient" rules={[ { type: 'text', }, { required: true, message: '재료를 입력하세요.', }, ]} hasFeedback > <Input.TextArea placeholder='재료를 입력하세요.' size='large' showCount maxLength={100} rows={5} /> </ContentFormWrapper> <ContentFormWrapper name="recipes" rules={[ { type: 'text', }, { required: true, message: '요리방법을 입력하세요.', }, ]} hasFeedback > <Input.TextArea placeholder='요리방법을 입력하세요.' size='large' showCount maxLength={1000} rows={20} /> </ContentFormWrapper> <ContentFormWrapper name="tips" rules={[ { type: 'text', }, ]} > <Input.TextArea placeholder='Tip을 입력하세요.' size='large' showCount maxLength={200} rows={8} /> </ContentFormWrapper> <Form.Item name="tags" rules={[ { type: 'text', }, ]} > <TagsInputWrapper placeholder='태그를 입력해 주세요.' size='large' /> </Form.Item> </PostingFormWrapper> </section> ) }; export default PostingForm;reducerconst reducer = (state = initialState, action) => { return produce(state, (draft) => { switch (action.type) { 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 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 = false; draft.addPostError = action.error; break; } }); }; export default reducer;sagafunction uploadImagesAPI(data) { console.log('사가의 데이터', data); return axios.post('/post/images', data); } function* uploadImages(action) { try { const result = yield call(uploadImagesAPI, action.data); yield put({ type: UPLOAD_IMAGES_SUCCESS, data: result.data, }) } catch(err) { yield put({ type: UPLOAD_IMAGES_FAILURE, data: err.response.data }) } } function addPostAPI(data) { return axios.post('/post', data); } function* addPost(action) { try { const result = yield call(addPostAPI, action.data); console.log(result.data); yield put({ type: ADD_POST_SUCCESS, data: result.data, }) yield put({ type: BOARD_ADD_POST_TO_ME, data: result.data, }) } catch(err) { yield put({ type: ADD_POST_FAILURE, data: err.response.data }) } } back/app.jsconst express = require('express'); const cors = require('cors'); const passport = require('passport'); const session = require('express-session'); const cookieParser = require('cookie-parser'); const dotenv = require('dotenv'); const morgan = require('morgan'); const path = require('path'); const postsRouter = require('./routes/posts'); const postRouter = require('./routes/post'); const userRouter = require('./routes/user'); const db = require('./models') const app = express(); const passportConfig = require('./passport'); dotenv.config(); db.sequelize.sync() .then(() => { console.log('db 연결 성공'); }) .catch(console.error); passportConfig(); app.use(morgan('dev')); app.use(cors({ origin: 'http://localhost:3060', credentials: true, })); app.use('/', express.static(path.join(__dirname, 'uploads'))); app.use(express.json({ limit: '100mb' })); app.use(express.urlencoded({ limit: '100mb', extended: true })); app.use(cookieParser(process.env.COOKIE_SECRET)); app.use(session({ saveUninitialized: false, resave: false, secret: process.env.COOKIE_SECRET, })); app.use(passport.initialize()); app.use(passport.session()); app.use('/posts', postsRouter); app.use('/post', postRouter); app.use('/user', userRouter); app.listen(3065, () => { console.log('서버 실행 중'); });back/post.jsconst express = require('express'); const multer = require('multer'); const path = require('path'); const fs = require('fs'); const { Post, Comment, Image, 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'); }, filename(req, file, done) { const ext = path.extname(file.originalname); const basename = path.basename(file.originalname, ext); done(null, basename + '_' + new Date().getTime() + ext); }, }), limits: { fileSize: 20 * 1024 * 1024 }, }); // data: { // imagePaths, // content: value, // } router.post('/', isLoggedIn, async (req, res, next) => { // addPostAPI / POST /post try { const post = await Post.create({ UserId: req.user.id, title: req.body.content.title, desc: req.body.content.desc, ingredient: req.body.content.ingredient, recipes: req.body.content.recipes, tips: req.body.content.tips, tags: req.body.content.tags, }); if (req.body.imagePaths) { if (Array.isArray(req.body.imagePaths)) { const images = await Promise.all(req.body.imagePaths.map((image) => Image.create({ src: image }))); await post.addImages(images); } else { const image = await Image.create({ src: req.body.imagePaths }); 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'], }] }); console.log(fullPost); res.status(201).json(fullPost); } catch (error) { console.error(error); next(error); } }); router.post('/images', isLoggedIn, upload.array('image'), async (req, res, next) => { try { console.log('라우터', req.files); res.json(req.files.map((v) => v.filename)); } catch (error) { console.error(error); next(error); } }); module.exports = router;
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문
완강했습니다.
안녕하세요 루키스 강사님 다름이 아니고 언리얼 데디케이트 서버로 게임을 만들려고 하는데 관련 강의 자료가 언리얼 공식 홈페이지 말고는 찾아볼게 없는 건가요?
-
미해결Jenkins를 이용한 CI/CD Pipeline 구축
강의자료! 쉐어! 요청!
학습에 사용되는 강의자료 공유가 필요한듯 합니다. 강의 자료 공유 부탁드립니다. 좋은 강의 감사 드립니다.
-
해결됨웹 개발자와 정보보안 입문자가 꼭 알아야 할 웹 해킹 & 시큐어 코딩
실습페이지가 버프스위트에 잡히지가 않습니다
인터셉트 켜도 실습페이지가 잡히질 않는데 어떻게 해야할가요 ㅜㅜ
-
해결됨[초급편] 안드로이드 커뮤니티 앱 만들기(Android Kotlin)
맥북 M1 쓰는데 안드로이드 스튜디오를 까니까 'No Android SDK found'라고 뜹니다. 어떻게 해야 하나요?
맥북 M1 쓰는데 안드로이드 스튜디오를 까니까 'No Android SDK found'라고 뜹니다. 어떻게 해야 하나요?
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
알고리즘 교안 매우사소한 오타(아닐수도있습니당...)
p4"\n"p23"기준"인것같습니다!!!p33"0 ~ 25" 인것같습니다 수강후기쓰기위해 후딱 공부하겠습니다!!
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
백준 1213번 질문
백준 1213번 푸는 중 질문이 생겨 글 올립니다.http://boj.kr/f0b468739ad24762a244c8fcecffa24c결과값은 맞는데, 틀렸다고 나옵니다.어떤 점이 문제가 될 수 있나요?
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
th: item 질문이있어요
html에서 th:value에서 item을 가져올때 이전에 add item에서도 model.addAttribute("item",item)으로 저장하고 editForm에서도 model.addAttribute("item",item)으로 저장하는데 html에서 타임리프가 item을 가져올때 어떻게 1번아이템인지 2번아이템인지 구분하고 값을 가져오는건가요?
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
백준 9996번 질문
안녕하세요 백준 9996번 문제 풀다가 질문 올립니다.http://boj.kr/c32649e80d26490ba805cdec30b90d3d결과값은 잘 나오는데 , 런타임 에러라고 뜹니다.어떤 부분이 잘못되었나요? (앞으로는 양식에 맞게 질문하겠습니다.)
-
미해결CS 지식의 정석 | 디자인패턴 네트워크 운영체제 데이터베이스 자료구조
이미지 스플리팅 용어
스플리팅이라는 용어보다는 이미지 스프라이트(sprite)라는 용어가 주로 쓰이는 것 같습니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
controller 패키지의 역할은 무엇인가요??
controller의 정확한 역할이 무엇인가요??controller라는 이름은 그냥 그렇게 쓰기로 한 암묵적인 약속인가요? 아니면 원래 문법상 그렇게 써야하는건가요??controller 안에 있는 파일들은 항상 @Controller로 감싸주는 것 맞나요???그리고 조금 논외이긴 한데 자바에서 패키지랑 디렉토리의 차이가 무엇인가요?? 아이콘이 달라서 차이가 있을거라고 생각되는데 정확한 차이를 모르겠습니다답변해주시면 감사하겠습니다 !!
-
미해결Slack 클론 코딩[실시간 채팅 with React]
만약 create react-app으로 프로젝트를 작업할 때에는
proxy 설정등의 webpack 설정은 어떤 파일에서 해야 하나요? 현재 강의와 같이 webpack.config.ts 파일을 생성하여서 설정하면 될까요?
-
미해결ERC20 깨부수기 (+ truffle, 프론트엔드)
migration 질문
'컴파일 및 코드 배포' 강의에서 truffle init을 하게 되면 이제 Migrations.sol파일이 없는데 그럼 last_completed_migration 변수의 역할은 없는거죠? 추가 컨트랙 파일 없이 truffle migrate를 해도 계속 1_ 파일부터 배포가 되어 여쭤봅니다
-
미해결[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
rangeslider에 대한 질문드리고 싶어요
안녕하세요~! 스승님 덕분에 즐겁고 유익한 플러터 공부를 하고 있습니다!다름이 아니라 궁금한 점이 있어서 질문을 남겨요위젯 중에 Rangeslider라는 위젯을 사용하여 만들고 싶은 것이 있는데 여기저기 검색을 해보아도 제가 못 찾는건지 알 수가 없더라구요 보통 검색해본 rangeslider는 일정한 최솟값과 최대값을 설정하고, 구간을 정해서 거기에 일정한 간격으로 자동 설정되는 것 같은데 특수한 값을 지정하고 그 사이에 stepsize 또한 다르게 설정하고 싶으면 어떻게 해야할까요? 예를들면 label은 0, 5000,25000,100000 이렇게 하고 0~5000 사이는 100, 200,300,500,1000,2000,3000,4000 이렇게 stepsize를 다르게 설정하려면 어떻게 해야할까요? 질문을 파악하시기 힘드시다면 하고자 하는 rangeslider가 구현된 어플이 있습니다.직방에서 보증금을 설정하기 위해 구현한 rangeslider입니다아래에 이미지는 첨부하였습니다 .꼭 도와주세요 스승님!!
-
미해결배민도 사용한다고? 환경설정 없는 백엔드 노코드 개발!
PORTAL 질문있습니다.
좌측 상단의 portal 대신 API PORTAL이 있는데, 화면 UI가 변경된 것일까요?Portal 기능을 이용할 수는 없나요 ?
-
미해결함수형 프로그래밍과 JavaScript ES6+
flatMap 관련 질문입니다.
const flatMap1 = pipe(L.flatMap, takeAll); const flatMap2 = curry(pipe(L.map, L.flatten, takeAll)); const flatMap3 = curry(pipe(L.flatMap, flatten)); //인자를 그대로 전달해주면 가능한데 // 또 다른 연산을 수행하면 오류남 log( flatMap1( (a) => a * a, [ [1, 2], [3, 4], [5, 6, 7], ] ) );log 찍을 때 인자를 그대로 전달하면 오류는 안 나는데 위처럼 하니까 NaN이 뜨더라구요그래서 map(a=>a*a) 이렇게 처리해서 해결은 했는데 혹시 다른 방법이 있을까요?
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
TypeError: Cannot destructure property 'mainPosts' of 오류 어디가 문제일까요...
찾다가 몰라서 오류 질문이요찾아도 안보입니다 ㅠㅠ어딘가 빼먹은건가요??연동이 안된건가요??코드 이중에 하나인가요? pages폴더 - index.jsimport React from 'react'; import { useSelector } from 'react-redux'; import AppLayout from '../components/AppLayout'; import PostCard from '../components/PostCard'; import PostForm from '../components/PostForm'; const Home = () => { const {me} = useSelector((state) => state.user); const {mainPosts} = useSelector((state) => state.post); return ( <AppLayout> {me && <PostForm />} {mainPosts.map((post) => <PostCard key={post.id} post={post} /> )} </AppLayout> ); }; export default Home;store 폴더 - configureStore.jsimport {createWrapper} from 'next-redux-wrapper'; import {createStore, applyMiddleware, compose} from 'redux'; import {composeWithDevTools} from 'redux-devtools-extension'; import createSagaMiddleware from 'redux-saga'; import reducer from '../reducers'; import rootSaga from '../sagas'; const loggerMiddleware = ({ dispatch, getState }) => (next) => (action) => { console.log(action); return next(action); }; const configureStore = () => { const sagaMiddleware = createSagaMiddleware(); const middlewares = [sagaMiddleware, loggerMiddleware]; const enhancer = process.env.NODE_ENV === 'production' ? compose(applyMiddleware(...middlewares)) : composeWithDevTools(applyMiddleware(...middlewares)) const store = createStore(reducer, enhancer); store.sagaTask = sagaMiddleware.run(rootSaga) return store; } const wrapper = createWrapper(configureStore, { debug: process.env.NODE_ENV === 'development', }); export default wrapper;package.json"dependencies": { "@ant-design/icons": "^4.7.0", "antd": "^4.23.1", "axios": "^0.27.2", "next": "^12.3.0", "next-redux-wrapper": "^6.0.2", "prop-types": "^15.8.1", "react-redux": "^8.0.2", "react-slick": "^0.29.0", "redux": "^4.2.0", "redux-devtools-extension": "^2.13.9", "redux-saga": "^1.2.1", "shortid": "^2.2.16", "styled-components": "^5.3.5", "update": "^0.7.4" }, "devDependencies": { "babel-eslint": "^10.1.0", "eslint": "^8.23.1", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.26.0", "eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-react": "^7.31.8", "eslint-plugin-react-hooks": "^4.6.0" } } 강의는 redux-saga 연동하기 부분이에요
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
Orders Microservice 수정 - MariaDB 듣던중 질문드립니다.
Orders Microservice 수정 - MariaDB강의 중에 db create table orders 하는데 @Entity가 Orders 가 있어서 jpa가 자동으로 테이블이 만들어버리네요강의 들을때는 일단 @Entity 막아두고 하면 될까요??
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
초기화의 정확한 의미
강의를 수강하다가 초기화의 정확한 의미가 잘 와닫지 않아서 질문드려봅니다.제가 이해하기로는 특정 값에 값을 set 할때 초기화한다라고 이해했는데 강의에서 .getName 도 초기화라고 표현이 되어 있더라고요이 초기화의 정확한 뜻이 무엇일까요?
-
미해결제대로 파는 Git & GitHub - by 얄코(Yalco)
안녕하세요. 깃허브 처음 수강하는 수강생입니다.
직장일이 바빠서 목차만 확인하고 아직 교육 수강을 못했습니다.수강전 문의를 했어야 하는데 수강전 문의를 할 줄 몰라서 커뮤니티에 올려봅니다.해당 깃허브를 익히면 원하는 오픈 소스코드를 찾아서 대입해볼 수도 있나요?예를 들어서 "지뢰찾기" 소스 코드를 공부하고 싶다면깃허브에 지뢰찾기 오픈소스 코드를 검색해서오픈 소스 코드를 확인하고 제 프로그램에 적용시키고, 공부할 수 있는지궁금합니다. 혹시 선생님께서 교육하시는 부분 중에깃허브에서 찾고 싶은 오픈소스 코드를 어떻게 찾는지 알려주는 항목도 있을까요?이것만 빨리 배워보고 싶습니다.아니면 처음부터 끝까지 완강하면 깃허브에서 제가 원하는 오픈소스 찾는 법을 자연스럽게 알게 될까요?