React로 NodeBird SNS 만들기
React로 NodeBird SNS 만들기
수강정보
(50개의 수강평)
911명의 수강생
공개하지 않은 강의입니다.
지식공유자 : 조현영
111회 수업 · 총 23시간 39분 수업
기간 : 평생 무제한 시청
수료증 : 발급 강의
수강 난이도 : 중급이상
이주호 프로필

multer 서버 업로드 이주호 6일 전
안녕하세요. 제로초님 multer 강좌 잘봤습니다. 다름이 아니라 원래 이미지 서버는 따로 두고 관리를 하잖아요? 하지만 multer는 done(null, 'uploade/image'); 이렇게하면 자기 폴더 안에 uploade/image 폴더를 찾아 업로드를 하는거잖아요?? 그러면 서버가 따로있으면 그 서버에 uploade/image 폴더 이렇게 넣어야하는데 그러면  아래처럼 앞에 서버 주소를 넣어줘야하나요? => 128.131.0.135/uploade/image 이렇게요 만약 이렇게된다쳐도 그러면 서버에 들어가면 user, 비밀번호를 넣어줘야하는거 아닌가요?? db 서버에 연결하는것처럼요.. 아니면 image서버를 따로두면 multer 못사용하는건가요? const uploade = multer({     storage: multer.diskStorage({         destination(req, file, done) {             if (file.mimetype === "image/jpeg" || file.mimetype === "image/jpg" || file.mimetype === "image/png") {                 done(null, '서버주소/uploade/image');             } else {                 done(null, '서버주소/uploade/file');             }         },         filename(req, file, done) {             const ext = path.extname(file.originalname);             const basename = path.basename(file.originalname, ext);             done(null, basename + new Date().valueOf() + ext);         }     }), });

3
rlaxodd93 프로필

안녕하세요 제로초님^^! 질문이 있습니다. rlaxodd93 7일 전
안녕하세요. 제로초님의 강의를 듣고 개인적으로 프로젝트를 만들고 있는 한 학생?입니다. 프로젝트는 거의 끝을 향해 달려가고 있지만 한달동안 고민했던 문제가 아직도 해결되지 않아서 이렇게 질문올립니다.! 1) 폰트사이즈 이런식으로 모바일화면에서 폰트사이즈를 작게하고 싶은데 저의 프로젝트에서 chrome모바일로 보면 최소 폰트사이즈가 8px라서 텍스트가 넘칩니다.  어떻게 하면 좋을까요? 2) 저의 프로젝트에 날짜마다 데이터를 조회할 수 있게 하는 기능이 있습니다. 요청올 때 마다 매번 DB에 해당 날짜를 조회하는게 불필요한 것 같아서 전역변수  var에 최근 10일의 데이터를 담아놓는데 괜찮은 방법인가요?  데이터는 'node-schedule'을 써서 1시간마다 데이터가 업데이트 되며 현재 22개의 전역변수가 선언되어있습니다. 3) const express = require('express'); async function Test(X){ }; router.post('/', async(req , res , next) =>{  await Test(X) }) 이런식으로 모든 함수들을 최상단으로  뺏는데 router안에 함수를 선언하는 것과 위로 함수를 빼는 것과 차이가 있나요? 감사합니다.!

6
꽃갈피 프로필

인피니트 스크롤링에 관한 질문입니다. 꽃갈피 10일 전
안녕하세요 :) 강의 7-11에서 LOAD_MAIN_POSTS_REQUEST가 중복 요청이 되어 useRef를 사용하여 해결을 하셨는데, 해시태그 페이지에서도 같은 문제가 발생해서 git에 올려놓으신 구버전(old branch) 소스코드나 강좌에서 참고하려했지만 useRef를 적용하는 것에 대한 설명이 없었습니다. 그래서 배운 내용을 스스로 적용해보던 와중에 문제가 생겨서 이렇게 질문을 남깁니다. 먼저 제가 수정한 코드는 아래와 같습니다. (제가 코드를 첨부하는데 제가 잘 다루지 못해서 그런지 javascript로 설정을 해도 계속 글씨가 제대로 보이지 않아서 굵은 글씨로 변경했습니다ㅜㅜ) 해시태그 페이지에서도 마찬가지로 LOAD_HASHTAG_POSTS_REQUEST 가 중복요청이 돼서 일단 saga에는watchLoadHashtagPosts의 takeLatest를 throttle로 수정하여 아래와 같은 코드로 바드로 바꿨습니다. function* watchLoadHashtagPosts() {      yield throttle(2000, LOAD_HASHTAG_POSTS_REQUEST, loadHashtagPosts);  } 그리고 Hashtag.js 는 useRef를 사용하여 아래와 같이 바꿨습니다. import React, { useEffect, useCallback, useRef } from 'react'; import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; import { LOAD_HASHTAG_POSTS_REQUEST } from '../reducers/post'; import PostCard from '../components/PostCard'; const Hashtag = ({ tag }) => {     const dispatch = useDispatch();     const { mainPosts, hasMorePost } = useSelector(state => state.post);     const countRef = useRef([]);     const onScroll = useCallback(() => {         if (window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight - 300) {             const lastId = mainPosts[mainPosts.length - 1] && mainPosts[mainPosts.length -1].id;             if (!countRef.current.includes(lastId)) {                 if (hasMorePost) {                     dispatch({                         type: LOAD_HASHTAG_POSTS_REQUEST,                         lastId,                         data: tag,                     })                 }                 countRef.current.push(lastId);             }         }     }, [hasMorePost, mainPosts.length, tag]);     useEffect(() => {         window.addEventListener('scroll', onScroll);         return () => {             window.removeEventListener('scroll', onScroll);         }     }, [mainPosts.length, hasMorePost, tag]);     return (         <div>             {mainPosts.map(c => (                 <PostCard key={+c.createdAt} post={c} />             ))}         </div>     ); }; Hashtag.propTypes = {     tag: PropTypes.string.isRequired, }; Hashtag.getInitialProps = async (context) => {      const tag = context.query.tag;     context.store.dispatch({         type: LOAD_HASHTAG_POSTS_REQUEST,         data: tag,     })     return { tag };  }; export default Hashtag; 그리고 버그는 아래와 같은 순서로 실행시키면 발생합니다. 1. 예를 들어 게시물이 25개 가량 있다고 가정을 합니다. 2. http://localhost:3060/hashtag/인프런 페이지에서 10개씩 게시물을 보여주는 인피니티 스크롤링을 한 번 해서 21번째 게시글의 #인프런 해시태그를 클릭합니다. 3. http://localhost:3060/hashtag/인프런 페이지가 로드될 때, 리덕스 devtools를 통해 액션어 어떻게 실행이 되는지 확인해보면 LOAD_HASHTAG_POSTS_REQUEST LOAD_HASHTAG_POSTS_REQUEST LOAD_HASHTAG_POSTS_SUCCESS LOAD_HASHTAG_POSTS_SUCCESS 이런 식으로 동작을 해서 게시물을 2번 로드해서 중복된 게시물이 보이게 됩니다. 4. console.log를 작성해서 확인해보면, 위와 같은 과정으로 실행시켰을 때 Hashtag.getInitialProps에서 뿐만 아니라 onScroll이 한 번더 실행이 돼서 dispatch로 인해 LOAD_HASHTAG_POSTS_REQUEST를 요청하는 것을 확인할 수 있었습니다. 왜 onScroll이 페이지가 새로 로드가 될 때 같이 실행이 되는지 모르겠습니다. 인피니트 스크롤링을 하지 않은 상태의  최신 10개 글 내에서 해시태그를 클릭하거나, 해당 해시태그 페이지를 새로고침하면 위와 같은 버그가 발생하지 않았고, 인피니트 스크롤링을 실행한 후 생성되는 게시물의 해시태그를 클릭하면 버그가 발생합니다.

8
devsn 프로필

안녕하세요 라우팅 관련 질문드립니다 devsn 12일 전
안녕하세요 아래 동적 라우팅 관련 질문한 회원입니다 계속 시도를 했지만, getServerside~ 는 gettet/setter를 반환을 했습니다. 스택오버플로우에서는 리턴값에 toJS를 넣어보라거나, 다른 방법도 제시했지만 똑같았네요 ㅠ 다른 커뮤니티에도 글을 올렸지만, 이렇다 할 해결책은 못 찾았습니다 ㅠㅠ 그래서 제가 생각을 한 것이, useRouter가 있다면, pages/[id]로 갈 때, 해당 url을 이용할 수도 있을 거 같았습니다. 실제로, 이를 사용해서 '동적 라우팅 스러운' 기능을 구현은 했습니다. 이 코드들이 next, react에 맞는 원리? (정확한 표현을 모르겠네요..) 일까요? 다시 말해, '기능 구현에만 급급한 건 아닌지' 궁금합니다. 제가 현재 프로젝트에서 다른 게시판도 이렇게 만들 거 같은데, 작성한 로직이 좋은 로직이 아니면 다시 공부해서 시도해 보려고 합니다 아래는 전체 코드구요, home화면에서 부터 게시판 클릭, 게시글 클릭해서 하는 케이스와 주소창에서 바로 id 값을 쳐서 게시글로 접속하는 케이스, 둘 다 정상적으로 읽혀집니다

2
devsn 프로필

안녕하세요 동적 라우팅 관련 질문드립니다 devsn 14일 전
안녕하세요 next, react, mobx, express, sequelize로 웹 개발을 하고 있습니다 게시판 기능 중에서 각 게시글을 동적 라우팅을 통해서 렌더링하려고 합니다.  getInitialProps를 하면은 이 함수 안에서는 값이 잘 읽힙니다만, 이거를 동적 라우팅 컴포넌트에 props로 전달할 때 undefined가 됩니다. Post 컴포넌트가 각 게시글들을 렌더링하는 컴포넌트입니다. div안의 내용은 잘 출력되고 있습니다. ((1, 2, 3번 함수가 있는데, 각각 주석처리 해 가면서 테스트했습니다)) 1번. 콘솔창에도 getInitialProps 관련 값들은 제가 클릭한 게시글의 db값들이 나옵니다, 다만, 이것이 Post컴포넌트의 props로 전달 될떄, 값이 undefine로 나옵니다. ((getInitialProps보다는 getServerSideProps를 사용하고 싶습니다)) 2번. 콘솔 자체가 안 찍힙니다... 3번. 2번과 마찬가지입니다.. 공식문서의 dynamic routes를 찾아봐도 3번 내용으로 시작하는 거 뿐이었는데, 제가 다른 문서도 봐야 할 것들이 있을까요? 아래는 백엔드의 코드입니다 (오른쪽 req의 더 오른쪽에는 res, next가 있습니다) 아래는 mobx의 다이내믹 관련 스토어입니다

9
devsn 프로필

antd 추가 질문드립니다 devsn 15일 전
안녕하세요 아래 질문에 이어서 추가 질문드립니다 (컴포넌트로 변경했습니다  ㅎㅎ...알려주셔서 감사합니다 ) 아래 처럼 메뉴 버튼이 있습니다 study-logs에 마우스를 클릭하는 것이 아닌, 마우스를 올렸을 때 아래처럼 파랗게 변합니다 css의 hover 효과가 antd Menu에 내장 되 있는 거 같은데요, 이와 마찬가지로, 아래 사진도 보여드릴게요 위 사진에서는 'react' 를 클릭했을 때 파랗게 강조가 되는 효과가 있습니다 이 antd에 내장되 있는 1. hover 효과, 2. 클릭했을 시 파란색 강조 효과 같은 것들을 없애기 위해서는 어떻게 해야 하는 지 궁금합니다.

1
devsn 프로필

안녕하세요 antd 관련 질문드립니다 devsn 15일 전
안녕하세요 antd를 사용해서 개인 웹 사이트를 만들고 있습니다 클릭했을 때 발생하는 antd 의 효과를 없애고 싶어서 styled-components를 사용했습니다 예를 들어서, 토글키를 클릭하면 하위 메뉴가 보이는 A버튼이 있다고 했을 때, A버튼을 눌렀을 때 파란색으로 글자색이 바뀌는 효과를 없애고 싶었습니다. 연습 삼아서 폰트 크기만 변경했는데, 변경이 되었습니다.  문제는, 토글 관련 함수들이 먹통이 되는 것입니다. antd의 효과를 없애기 위해서는, 스타일드 컴포넌트로 변경을 하는게 아니라, 그냥 처음부터, antd를 쓰지 않고, 제가 원하는 효과를 적용하면서 메뉴를 구성하는 방법 뿐일까요? 아래는 코드입니다 ( 어떤 코드냐면, 'study-logs'라는 버튼을 누르면 react, next, js 라는 하위 메뉴 버튼이 토글 형식으로 생성되는 것입니다 ) <SubMenu key="sub2" icon={<LaptopOutlined />} title="study-logs"> <Menu.Item key="5">react</Menu.Item> <Menu.Item key="6">next</Menu.Item> <Menu.Item key="7">js</Menu.Item></SubMenu>위의 코드를 아래처럼 바꾸었습니다.-- const TextSubmenu = styled('SubMenu')` font-size: 24px;` <TextSubmenu key="sub2" icon={<LaptopOutlined />} title="study-logs"> <Menu.Item key="5">react</Menu.Item> <Menu.Item key="6">next</Menu.Item> <Menu.Item key="7">js</Menu.Item></TextSubmenu>여기서 폰트사이즈를 변경한 것은, 실제css가 적용이 되는지 테스트 해 보기 위함이었고,실제로 폰트 사이즈가 변경은 되었습니다.하지만, 기존에 있던 기능들이 작동을 안 합니다.

2
김로인 프로필

제로초님 김로인 16일 전
제로초님 안녕 하세요  공부 하다가 궁금 한 점이 생겨 질문을 답니다. react-creact-app으로 만들었을 때 새로 고침시 서버 에러가 나지 않고  직접 처음 부터 만들었을 때는 새로 고침시 서버 에러가 나더라구여  이게 react-creact-app으로 개발을 했을 때는 기초 셋팅을 해줘서 그런 것 같은데  직접 처음 부터 만들 때는 새로 고침시 에러가 나지 않으려면 웹팩에서 historyApiFallback: true 같은 걸로 설정을 해줘야 하나요? 아니면 프록시 설정을 해줘야 하는건지 어떤 방법이 있는지 해서 질문 남깁니다

1
devsn 프로필

안녕하세요 리액트 관련 질문드립니다 devsn 17일 전
리액트 강의를 듣고, 성능에 관심이 생겼습니다 1. 성능을 올리기 위해서는 React.memo, useCallback, useMemo로 할 수 있는 것 말고도 다른 방법이 있을까요? 2. 추가적으로 공부해야 하는 부분이 있을까요?  3.성능을 올린다고 했을 때, 그것을 전후 수치로 나타내는 툴이 있는 지 궁금합니다

2
tagooon 프로필

공부하다가 하도 해결안되어 질문 남깁니다 ㅠㅠ tagooon 27일 전
안녕하세요 저는 제로초님의 강의를 통해 리액트를 공부하고있는 사람입니다. 혼자 공부하던중 도무지 해결안되는 부분이 있어서 이렇게 질문을 남깁니다. ------------------------------------------------------------------------------------   const [isChecked, setIsChecked] = useState([]);   const [amllShopList, setAmllShopList] = useState([]); const handleAddRow = (e) => {   //추가버튼     e.preventDefault();     const newRow = {       shopNm : '',       shopTel : '',       shopAddr : '',       shopBrn : ''     }     setAmllShopList([...amllShopList,newRow]);   }   const handleListEdit = (index, name, value) => {     //내용수정     setAmllShopList(produce(amllShopList,(draft) => {draft[index][name]=value}));   }   const handleDelRow = (e) => {   //삭제버튼(체크박스 선택한것들)     e.preventDefault();     //if(isEmpty(isChecked)) return showAlert('삭제할 지점을 선택해주세요.');     // const resData = amllShopList.filter((data,i)=> !isChecked[i]);     // setAmllShopList(resData);     setAmllShopList(amllShopList.filter((data,i)=>!isChecked[i]));     setIsChecked([]);   }   const handleCheckRow = (e) => {   //체크박스 선택     const index = parseInt(e.target.name);     isChecked[index] = !isChecked[index];     setIsChecked([...isChecked]);   };   <>             <div>             <h5 className="mb8 mt40" style={{ display: 'inline-block', verticalAlign: 'top' }}>             지점 등록             </h5>                   <Button size="sml" background="gray" title="추가" width={80} height={40} buttonMarkup={true} onClick={handleAddRow} />       <Button size="sml" background="gray" title="삭제" width={80} height={40} buttonMarkup={true} onClick={handleDelRow} /> ----------렌더링하는부분--------               {amllShopList.map((row, i) =>                  <AmllShopList key={i} rowNum={i} isChecked={isChecked[i]} onCheckRow={handleCheckRow} onEdit={handleListEdit}/>             )}               </tbody>             </table>           </> -------------------------------- ---------컴포넌트----------------------------- export const AmllShopList = ({rowNum, isChecked, onCheckRow, onEdit}) => {  const handleAmllCheck = (e) => {    onCheckRow(e);  };  const handleInputChange = (e) => {    const name = e.target.name;    const value = e.target.value;    onEdit(rowNum, name, value);  };  return(    <tr>      <td><CheckBox id={'chk_row-'+rowNum} name={rowNum} checked={isChecked} onChange={handleAmllCheck}/></td>      <td><Input type="text" id={'shopNm-' + rowNum} name="shopNm"   onChange={handleInputChange} /></td>      <td><Input type="text" id={'shopTel-' + rowNum} name="shopTel"   onChange={handleInputChange} /></td>      <td><Input type="text" id={'shopAddr-' + rowNum} name="shopAddr"  onChange={handleInputChange} /></td>      <td><Input type="text" id={'shopBrn-' + rowNum} name="shopBrn"   onChange={handleInputChange} /></td>    </tr>  )} ----------------------------------- 원하는 형태는 추가버튼을 통해 amllShopList 배열에 객체 데이터를 추가하여 값을 입력할수있고,  체크박스를 통해 삭제할수있는 기능을 구현하는것이었으나, 현재 상황은 추가하고 데이터의 입력은 가능하지만 체크박스로 체크하여 삭제를 할경우 실제 상태값은 정상적으로 삭제가 되고있으나, 화면상으로는 가장 마지막 데이터가 지워지는것처럼 보이게 됩니다. ex) 추가버튼을 5번 눌러 객체를 5개 추가하여 3,4번째 객체를 체크하여 삭제할경우, 화면상으로는 1,2,3번 데이터가 보이게되지만 실제 데이터는 1,2,5번 데이터가 남아있는상태로 api에 들어가게됨. 해결법좀 알려주세요 ㅠㅠ

1
aloha_jh 프로필

혹시 디비 테이블을 그린다면 이게 맞는걸까요? aloha_jh 1달 전
그리고 workbench 에 테이블이 5개생기는데 나머지 테이블은 뷰같은 개념인건가요? ㅜ 시퀄라이즈 헷갈리네요..

1
EUN 프로필

좋아요 버튼 눌리는 문제... 상세페이지와 연동이 이상한 것 같습니다 EUN 1달 전
깃허브 주소 https://github.com/jinne202/maplebird 질문이 조금 복잡할 수 있는데, 좋아요 버튼을 메인페이지에서 누르면 fail이 뜨면서 눌러지지 않는데, 좋아요 버튼을 상세페이지에서 누르면 (post/id) 눌러집니다. 또한 같은 상태에서 메인 페이지에 다시 돌아오면 다시 또 좋아요 버튼이 눌러집니다 ㅠㅠreducer에서 singlePost : {~~} 이 부분을 주석처리하면 메인페이지에서도 버튼이 잘 눌러지는데, 어떤 문제인지 짐작하기가 어렵습니다. consle.log로 눌릴 때 마다 post id를 찍어봤는데 메인 페이지에서도 post id를 잘 체크하고 있어서 어떤 부분에서 오류가 나는지 체크하기가 어렵습니다 ㅠㅠ 메인 페이지에서는 post.id랑 singlePost에서 id를 파악하는데 뭔가 문제가 있는건지 ㅠㅠ... 혹시 몰라서 깃 주소도 같이 올립니다...!  코드  <reducer> <saga> <back singlePost>

6
윤희중 프로필

const liked = post.Likers.find((v) => v.id === id) 에러문제 윤희중 1달 전
안녕하세요 다른사람의 글을 트윗버튼을 누르면 find함수를 못찾는다는 에러가뜹니다. 분명히 포스트내에는 Likers라는 객체가있는데 말이죠 도와주세요

2
이주호 프로필

댓글 검색 쿼리문으로 이주호 1달 전
안녕하세요. 지금 현재 쿼리문으로 한번 구현을하고 있는데  아래 처럼 query를 하고싶은데 JOIN을 하는건 알겠는데 이게 무슨 JOIN을 해야지 이렇게 같이 데이터가 들어가는지 잘 모르겠네요.  where: {                 PostId: req.params.id,             },             order: [[                 'createdAt', 'ASC'             ]],             include: [{                 model: db.User,                 attributes: ['id', 'nickname'],            }],

4
이주호 프로필

게시글 이미지 query문으로 이주호 1달 전
        let post = req.body;         let sql = 'INSERT INTO test(`title`, `desc`, `addFile`) VALUES(?, ?, ?)';         let params = [            post.forum_select,            post.forum_title,            post.forum_content,         ];         if(post.post_data_imfl) {             if(Array.isArray(post.post_data_imfl)) { //프론트에서 보낸 이미지가 배열이라면                 await Promise.all(post.post_data_imfl.map((image) => {                     params.push(image);                 }));                 await conn.query(sql, params, (err, rows) => {                     err ? console.error(err) : res.json(rows)                 })             } else {                 await params.push(post.post_data_imfl )                 await conn.query(sql, params, (err, rows) => {                     err ? console.error(err) : res.json(rows)                 })            } 제로초님 강의를 보고 그냥 쿼리를 해봤는데 제가 한거는 몇개를 올려도 첫번째 이미지만 올라가네요.... 시퀄라이즈만 되는건가요??

6
지식공유자 되기
많은 사람들에게 배움의 기회를 주고,
경제적 보상을 받아보세요.
지식공유참여
기업 교육을 위한 인프런
“인프런 비즈니스” 를 통해 모든 팀원이 인프런의 강의들을
자유롭게 학습하는 환경을 제공하세요.
인프런 비즈니스