묻고 답해요
167만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
리액트 쿼리 SSR 부분 질문있습니다.
강의 프로젝트를 제로초님 깃헙 코드 참고해서 리액트 쿼리로 다시 만들어 보는중인데요 회원가입 페이지에 SSR 적용하는 과정에서 다음과 같은 에러가 납니다. 코드를 보면//pages/signup.tsx export const getServerSideProps = async (context: GetServerSidePropsContext) => { const cookie = context.req ? context.req.headers.cookie : ''; axios.defaults.headers.Cookie = ''; if (context.req && cookie) { axios.defaults.headers.Cookie = cookie; } const response = await loadMyInfoAPI(); if (response.data) { return { redirect: { destination: '/', permanent: false, }, }; } return { props: {}, }; }; // api/user.ts export function loadMyInfoAPI() { return axios.get('/user').then((response) => response.data); } // routes/user.js router.get('/', async (req, res, next) => { try { if (req.user) { const fullUwerWithoutPassword = await User.findOne({ where: { id: req.user.id }, attributes: { exclude: ['password'] }, include: [ { model: Post, attributes: ['id'] }, { model: User, as: 'Followings', attributes: ['id'] }, { model: User, as: 'Followers', attributes: ['id'] }, ], }); res.status(200).json(fullUwerWithoutPassword); } else { res.status(200).json(null); } 로그인안한 상태에서 유저 정보를 불러오면 null이 반환되서 에러가 나는거 같은데요 const response = await loadMyInfoAPI(); if (response.data) { return { redirect: { destination: '/', permanent: false, }, }; } 이부분을 지우고 다음과 같이 바꿔주면export const getServerSideProps = async (context: GetServerSidePropsContext) => { const cookie = context.req ? context.req.headers.cookie : ''; axios.defaults.headers.Cookie = ''; if (context.req && cookie) { axios.defaults.headers.Cookie = cookie; } return { props: {}, }; }; 에러가 사라지는데 지워도 상관없는건가요??
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
process.env.REACT_APP_MOVIE_DB_API_KEY를 찾지 못하고 있어요
.env 생성하고 axios.js에서 process.env.REACT_APP_MOVIE_DB_API_KEY를 찾지 못하고 있어요process.env.REACT_APP_MOVIE_DB_API_KEY=00000000
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
삭제하기 기능 구현 레퍼런스 코드는 없을까요
게시글 상세 화면에서 삭제하기 기능을 구현해주세요.이부분에 대한 레퍼런스 코드가 깃허브에 등록된 내용에는 나오지 않는데 알고 싶습니다
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
css in js 관련 질문드립니다!
안녕하세요! 현재 리액트 초반부 강의 수강중에 있습니다.포트폴리오 코딩중에 있는데 css in js 에서 일반적인 css에서 처럼 전체선택자 *를 사용하여box-sizing: border-box; 로 하고싶은데 검색하봐도 방법이 나오지 않습니다.. css in js 에서 전체선택자는 어떤식으로 사용할 수 있을까요?MDN 처럼 css in js 관련 아카이브가 따로 있을까요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
section27 퀴즈 질문입니다.
등록 시 화면 페이지는 바뀌는데 바뀌자마자 위와 같은 오류가 떠서 계속 찾아보는데 혼자는 해결하기 어려워 여쭤봅니다 ㅠㅠ 어디가 틀린 걸까요? mutation은 제대로 된 걸 확인했는데 fetch가 안 되네요.폴더 구조는05/boards/new index.js05/boards/products/[productId] index.jsimport { useState } from "react"; import { useMutation, gql } from "@apollo/client"; import { useRouter } from "next/router"; const CREATE_PRODUCT = gql` mutation createProduct( $seller: String $createProductInput: CreateProductInput! ) { createProduct(seller: $seller, createProductInput: $createProductInput) { _id number message } } `; export default function ProductRegPage() { const router = useRouter(); const [seller, setSeller] = useState(); const [name, setName] = useState(); const [detail, setDetail] = useState(); const [price, setPrice] = useState(); const [createProduct] = useMutation(CREATE_PRODUCT); const onClickRegister = async () => { try { const result = await createProduct({ variables: { seller, createProductInput: { name, detail, price, }, }, }); console.log(result); router.push(`/05/boards/products/${result.data.createProduct._id}`); } catch (error) { alert(error.message); } }; const onChangeSeller = (event) => { setSeller(event.target.value); }; const onChangeName = (event) => { setName(event.target.value); }; const onChangeDetail = (event) => { setDetail(event.target.value); }; const onChangePrice = (event) => { setPrice(parseInt(event.target.value)); }; return ( <div> 판매자: <input type="text" onChange={onChangeSeller} /> 상품명: <input type="text" onChange={onChangeName} /> 상품내용: <input type="text" onChange={onChangeDetail} /> 상품가격: <input type="text" onChange={onChangePrice} /> <button onClick={onClickRegister}>상품 등록</button> </div> ); } import { useQuery, gql } from "@apollo/client"; import { useRouter } from "next/router"; const FETCH_PRODUCT = gql` query fetchProduct($productId: ID) { fetchProduct(productId: $productId) { seller name detail price } } `; export default function ProductDetailPage() { const router = useRouter(); console.log(router); const { data } = useQuery(FETCH_PRODUCT, { variables: { productId: router.query.productId }, }); console.log(data); return ( <div> <div>판매자:{data ? fetchProduct?.seller : "loading..."}</div> <div>상품명:{data ? fetchProduct?.name : "loading..."}</div> <div>상품내용:{data ? fetchProduct?.detail : "loading..."}</div> <div>상품가격:{data ? fetchProduct?.price : "loading..."}</div> </div> ); }
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
.eslintrc.js module 키워드에 빨간밑줄
위와 같은 에러가 생기는데 규칙을 검사하는 건 문제가 없긴합니다. 에러 내용을 번역해서 봤는데도 무슨 말인지 잘 모르겠고 어떻게 해결해야하는지 감도 안옵니다..
-
해결됨손에 익는 Next.js - 공식 문서 훑어보기
다음 영상에서는 메뉴좀 크게보이게 해주세요.
노트북에서 보면 프로젝트 디렉토리 폴더/파일들이 너무 작아서 안보이네요.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
27:25초에 나의그래프큐엘셋팅 파일로 이동하는방법
27:25초에 나의그래프큐엘셋팅 파일로 바로 이동해지는데 어떻게 하는걸까요
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
안녕하세요. 게시글 필터링 관련해서 질문이있습니다.
안녕하세요. 현재 여러개의 select - option으로 게시된 게시글을 필터링을 해보려고 하고 있고 잘 작동하는데 코드가 너무 지저분합니다. 혹시 좀더 효율적으로 짤 수 있는 팁주실수 있으면 감사하겠습니다. ㅠㅠ const coursePosts = useSelector((state) => state.coursePost.coursePosts); const [group, setGroup] = useState("all"); const [subject, setSubject] = useState("all"); const [level, setLevel] = useState("all"); const fillteredCoursePosts = coursePosts.filter((post) => ( //문제의 부분 start group === 'all' && subject === 'all' && level === "all" ? post : subject === 'all' && level === "all" ? (post.group === group) : group === 'all' && level === "all" ? (post.subject === subject) : group === 'all' && subject === "all" ? (post.level === level) : group === "all" ? (post.subject === subject) && (post.level === level) : subject === "all" ? (post.group === group) && (post.level === level) : level === "all" ? (post.group === group) && (post.subject === subject) : (post.group === group) && (post.subject === subject) && (post.level === level) ) //문제의 부분 End ) const handleGroupChange = (e) => { setGroup(e.target.value); } const handleSubjectChange = (e) => { setSubject(e.target.value); } const handleLevelChange = (e) => { setLevel(e.target.value); } return ( <> <main className="width_content"> <div className={styles.course_box_wrap}> <div className={styles.filter_header}> <div className={styles.ft_select}> <select onChange={handleGroupChange}> <option value="all">ALL</option> <option value="Group1">Group 1</option> <option value="Group2">Group 2</option> <option value="Group3">Group 3</option> </select> <select onChange={handleSubjectChange}> <option value="all">ALL</option> <option value="English">English</option> <option value="Korean">Korean</option> </select> <select onChange={handleLevelChange}> <option value="all">ALL</option> <option value="Core">Core</option> <option value="test1">Embed</option> <option value="test2">Test</option> </select> </div> </div> </div> </main> </> ) }
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
포트폴리오 31-1 과제 중 오류, password is not defined
포트폴리오 과제 중, 게시물을 등록하고 수정할 때 비밀번호를 똑같이 입력했는데 저런 오류가 뜹니다 ....ㅠ 해결방법을 잘 모르겠습니다!
-
미해결[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
newAccessToken 이 바로 적용되지 않습니다
const errorLink = onError(({ graphQLErrors, operation, forward }) => { //1. 에러 캐치 if (typeof graphQLErrors !== "undefined") { for (const err of graphQLErrors) { //1-2. 해당 에러가 토큰만료 에러인지 체크 if (err.extensions.code === "UNAUTHENTICATED") { return fromPromise( //2. refreshtoken으로 accessToken을 재발급 받기 getAccessToken().then((newAccessToken) => { setAccessToken(newAccessToken ?? ""); //3. 재발급 받은 accesstoken 으로 방금 실패한 쿼리 실행하기 operation.setContext({ header: { ...operation.getContext().headers, //기존의 authorization: Bearer '만료된 토큰' Authorization: `Bearer ${newAccessToken}`, //3-2 authorization 만 바꿔치기 }, }); }) ).flatMap(() => forward(operation)); //3-3 방금 수정한 쿼리 재요청하기 } } } });수업이랑 동일하게 코드를 작성하였으나 버튼을 눌러도 재발급된 accessToken 이 들어가지 않아 error 가 발생하고 2번이상 눌러야지만 accesstoken 이 제대로 수정되서 정상적으로 실행됩니다. 어디가 문제일까요?
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
쿠키 저장이 되지 않습니다.
res.set("Set-Cookie", cookie.serialize("token", token, { httpOnly: true, maxAge: 60 * 60 * 24 * 7, path: "/", }))프론트에 credentials을 true로 하고 cors 부분에도 credentials를 true로 했지만 application/cookie에 저장이 되지 않습니다. header에 response로 토큰은 잘 들어오는데 뭐가 문제일까요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
리액트 깃허프
리액트 작업을 컴퓨터 이동하면서 하고싶은데 usb론 너무오래걸려서 깃헙으로 하고싶은데 깃헙에 빌드해서 올리면 다시 받을때 어떻게 받아서 작업해야할까요
-
미해결[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
스터디 관련 질문
안녕하세요! 해당 강의를 통해 프론트엔드 기술을 학습 중인 취준생입니다. 본 학습 자료의 저작권은 코드캠프에 있어 무단 도용, 배포, 복제를 금지한다고 적혀있는데 그럼 혹시 개인 블로그에 내용을 공부한 내용을 정리하는 것이 문제가 되는 사항인지 여쭤봅니다!
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
이 프로젝트를 배포해서 실서비스로 사용할 수 있나요?
새로운 기능을 붙여서 배포해 서비스하려고 합니다.예외처리 같은 것을 추가해서 배포해도 문제가 없을까요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
Server Cannot be Reached
vscode에서 계속 오류 떠서 playground에서 보내보았는데 server cannot be reached가 계속 뜨면서docs도 무한 로딩중이에요 ㅠ
-
해결됨Next.js 시작하기(feat. 지도 서비스 개발)
SSR vs SSG
안녕하세요 강의 정말 잘 듣고있습니다!SSG가 SSR보다 사용자 경험이 좋은건 이해했습니다! 근데 한가지 더 의문점인건 SSG가 아니고 SSR을 선택해야하는 케이스가 있을까요? 라는 의문이 듭니다! 예를 들면 검색결과 페이지라던가 매번 매순간 페이지의 내용이 달라지는 페이지라면 SSG가 아니고 SSR로 만드는게 더 적합한 그런 케이스가 실무에서 있을까요?
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
안녕하세요, 리덕스를 통해서 좋아요 기능구현을 해보고 있는데 디스패치와 충돌이 나는것 같습니다.
안녕하세요, 좋은 강의 감사드립니다. 제가 좋아요 기능구현을 해보고 있는데, 클릭이 되면 state(clicked)를 통해 true로 만들어서 빨강색으로 만들고 1를 추가시키고 다시 클릭하면 false가 되면서 검게 되고 1을 감소하게 하는 기능을 구현하려고 하는데요. 각각 빨/검 1추가시키기는 되는데 둘이 합치려니까 1을 올리면서 리렌더링이 되고 clicked라는 스테이트가 바로 false로 초기화되버리는것 같습니다. 혹시 방법이있을까요? 뭐라고 검색해야 할지 감이 잘안잡혀서 질문남깁니다. const Heart = ({ pageId, id, currentIndex, postId, }) => { const dispatch = useDispatch(); const { coursePosts } = useSelector((state) => state.coursePost); const { clicked, setClicked } = useState(false); const heart = coursePosts[currentIndex].CourseReview[id].heart; const onClickHeart = () => { if (!clicked) { dispatch(coursePostActions.clickCourseReviewHeart({ pageId, postId })) } else { dispatch(coursePostActions.clickCourseReviewHeartAgain({ pageId, postId })) } setClicked(!clicked); } return ( <button type="button" onClick={onClickHeart} className={clicked === true ? styles.active : ""}> <FontAwesomeIcon icon={faHeart} /> <span>{heart}</span> </button> ); }; export default CourseReviewItems;const coursePostSlice = createSlice({ name: "coursePost", initialState, reducers: { clickCourseReviewHeart(state, action) { const postIndex = state.coursePosts.findIndex((v) => v.id === Number(action.payload.pageId)); const reviewIndex = state.coursePosts.findIndex((v) => v.id === action.payload.postId); state.coursePosts[postIndex].CourseReview[reviewIndex].heart += 1 }, clickCourseReviewHeartAgain(state, action) { const postIndex = state.coursePosts.findIndex((v) => v.id === Number(action.payload.pageId)); const reviewIndex = state.coursePosts.findIndex((v) => v.id === action.payload.postId); state.coursePosts[postIndex].CourseReview[reviewIndex].heart -= 1 } }
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
강좌 끝나고 댓글 수정 기능 만들어 보고 있습니다
{commentFormOpened && ( <div> {commentEditMode ? <CommentContent post={post} commentEditMode={commentEditMode} onClickUpdateComment={onClickUpdateComment} onCancelUpdateComment={onCancelUpdateComment} /> : ( <> <CommentForm post={post} /> <CommentContent post={post} commentEditMode={commentEditMode} onClickUpdateComment={onClickUpdateComment} onCancelUpdateComment={onCancelUpdateComment} /> </> ) } </div> )} //PostCard.js import React, { useCallback, useEffect, useState } from 'react'; import { Avatar, Comment, List, Input, Button, Popover } from 'antd'; import { useDispatch, useSelector } from 'react-redux'; import Link from 'next/link'; import PropTypes from 'prop-types'; import { EllipsisOutlined } from '@ant-design/icons'; import { UPDATE_COMMENT_REQUEST } from '../reducers/post'; const {TextArea} = Input; const CommentContent = ({ post, onCancelUpdateComment, commentEditMode, onClickUpdateComment }) => { const dispatch = useDispatch(); const id = useSelector((state) => state.user?.me.id); const { updateCommentLoading, updateCommentDone } = useSelector((state) => state.post); const [editText, setEditText] = useState(post.Comments.content); useEffect(() => { if (updateCommentDone) { onCancelUpdateComment(); } }, [updateCommentDone]); const onChangeCommentText = useCallback((e) => { setEditText(e.target.value); }, []); const onChangeComment = useCallback(() => { dispatch({ type: UPDATE_COMMENT_REQUEST, data: { PostId: post.id, CommentId: post.Comments.id, UserId: id, content: editText, }, }); }, [post, id, editText, post.Comments.id]); return ( <div> {commentEditMode ? ( <> <TextArea value={editText} onChange={onChangeCommentText} /> <Button.Group> <Button loading={updateCommentLoading} onClick={onChangeComment}>수정</Button> <Button type="danger" onClick={onCancelUpdateComment}>수정 취소</Button> </Button.Group> </> ) : <List header={`${post.Comments.length}개의 댓글`} itemLayout="horizontal" dataSource={post.Comments} renderItem={(item) => ( <li> <Comment actions={[<Popover key="more" content={ <Button.Group> {id && item.User.id === id ? ( <> <Button onClick={onClickUpdateComment}>수정</Button> <Button type="danger"> 삭제 </Button> </> ) : ( <Button>신고</Button> )} </Button.Group> } > <EllipsisOutlined /> </Popover>,]} author={item.User.nickname} avatar={ <Link href={`/user/${item.User.id}`}> <a><Avatar>{item.User.nickname[0]}</Avatar></a> </Link> } content={item.content} /> </li> )} /> } </div> ) } CommentContent.propTypes = { post: PropTypes.shape({ id: PropTypes.number.isRequired, Comments: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.number.isRequired, content: PropTypes.string.isRequired, })) }), onCancelUpdateComment: PropTypes.func.isRequired, onClickUpdateComment: PropTypes.func.isRequired, commentEditMode: PropTypes.bool }; CommentContent.defaultsProps = { commentEditMode: false, } export default CommentContent; //CommentContent.js case UPDATE_COMMENT_REQUEST: draft.updateCommentLoading = true; draft.updateCommentDone = false; draft.updateCommentError = null; break; case UPDATE_COMMENT_SUCCESS: draft.updateCommentLoading = false; draft.updateCommentDone = true; const post = draft.mainPosts.find((v) => v.id === action.data.PostId); post.Comments = post.Comments.find((v) => v.id === action.data.CommentId); post.Comments = post.Comments.find((v) => v.id === action.data.UserId); post.Comments.content = action.data.content; break; case UPDATE_COMMENT_FAILURE: draft.updateCommentLoading = false; draft.updateCommentError = action.error; break; //reducers/post.js function updateCommentAPI(data) { return axios.patch(`/post/${data.PostId}/comment`, data); } function* updateComment(action) { try { const result = yield call(updateCommentAPI, action.data); yield put({ type: UPDATE_COMMENT_SUCCESS, data: result.data, }); } catch (err) { console.error(err); yield put({ type: UPDATE_COMMENT_FAILURE, error: err.response.data, }); } } // sagas/post.js router.patch('/:postId/comment', isLoggedIn, async (req, res, next) => { // PATCH post/2/comment try { await Comment.update({ content: req.body.content, }, { where: { PostId: req.params.postId, UserId: req.user.id, }, }); res.status(200).json({ PostId: parseInt(req.params.postId, 10), UserId: req.user.id, content: req.body.content, }); } catch (error) { console.error(error); next(error); } }); //routes/post.js이렇게 PostId, UserId, content가 보내지고, 실패가 뜨면서 새로고침을 하면 해당 글에 달았던 댓글들이 모두 다 "zzz"로 변경되어 있습니다. 그래서 CommentId를 보내줘야 될 거 같은데 여기서 막혀서 감이 도무지 잡히질 않습니다.
-
해결됨Next.js 시작하기(feat. 지도 서비스 개발)
NoSSR 관련한 질문입니다:)
강의후반부에 window에 접근하는 상황인 NoSSR을 수강하면서 해당 상황이 어떤 케이스인지 확인차 질문 남깁니다.Next에서 window나 document같이 WebAPI에 기재된 객체들에 접근하는 코드를 쓸 때 백엔드 단에서 접근이 불가하니, dynamic을 사용한다 정도로 이해하면 되려나요?.? 이와는 다르게, useEffect의 경우 브라우저에서 렌더가 될 때 코드가 돌아가니까 WebAPI에 접근이 가능하다 정도로 이해하면 되려나요?.?