묻고 답해요
167만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨만들면서 배우는 프론트엔드 DO IT 코딩 (Next.js, Typescript)
useState의 set 함수에 대해서 질문이 있습니다.
useState의 set 함수가 비동기로 실행된다고 이해하고 있는데setLoading(true); setAuthUser({ uid: authState.uid, email: authState.email, photoURL: authState.photoURL, displayName: authState.displayName, }); setLoading(false);이 부분의 코드가 어떻게 순서대로 실행이 되는건가요? set 함수끼리는 순서가 지켜지나요?
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
VsCode : Import하지 않은 컴포넌트 경고표시X(설정?)
현재 버전 정보들입니다 "next": "^11.1.4", "prop-types": "^15.8.1", "eslint": "^8.33.0", "eslint-plugin-import": "^2.27.5", "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0"TypeScript와 React를 사용해서 프로젝트 했을 때는 VsCode에서(웹스톰만의 기능은 아니라고 생각합니다.) import하지 않은 컴포넌트에 대한 경고문이 나와서, 맥북 기준 커맨드+.을 하면 Code Action으로 import을 시켜줄 수 있었습니다.그런데강의를 진행하면서 컴포넌트를 import하지 않은 상황인데도 불구하고, 따로 경고문이 나타나지 않는데, 이게 어떤 설정을 해야하는건지 잘 모르겠습니다.<Menu /> , <Col /> , <UserProfile /> 같은 컴포넌트들입니다.(코드는 이 정도만 첨부하겠습니다.)import PropTypes from "prop-types"; import Link from "next/link"; import { Menu, Input, Row, Col } from "antd"; ... <Row gutter={8}> <Col xs={24} md={6}> {isLoggedIn ? <UserProfile /> : <LoginForm />} </Col> <Col xs={24} md={12}> {children} </Col> <Col xs={24} md={6}> <a href="https://velog.io/" target="_blank" rel="noreferrer noopener">Velog</a> </Col> </Row> </div> ); }; AppLayout.propTypes = { children: PropTypes.node.isRequired, }; export default AppLayout;Import되지 않은 컴포넌트인 <UserProfile />, <LoginForm /> 경고문이 뜨지 않는 사진도 첨부했습니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
수정 페이지 마운트 직후, 온체인지 핸들러가 인풋 값을 ""으로 인식하여, 인풋 값를 지웠을 경우, 온체인지 핸들러가 값의 변동을 인식하지 못하는 문제가 있습니다.
안녕하세요 강의 잘 보고있습니다.수정 페이지 마운트 직후, 온체인지 핸들러가 인풋 값을 ""으로 인식하고, 인풋 값를 지웠을 경우, 온체인지 핸들러가 값의 변동을 인식하지 못하는 문제가 있습니다.즉, 수정 페이지의 각 인풋 디폴트 값들에 데이터가 불러와진 후, 값을 입력하는 것이 아니라 삭제할 경우에 값의 변동을 온체인지 핸들러가 인식하지 못하여 발생합니다.따라서, 인풋의 온체인지 핸들러를 통해 인풋 값들이 비어있는지 확인하는 유효성 검사에 작은 오류가 있습니다. 수정페이지 마운트 직후 데이터를 불러온 뒤, 값이 인풋에 입력된 후, 온체인지핸들러가 변동을 인식하게 할 수 있을까요? 혹시 비슷한 인풋 값들을 객체에 묶어 저장하는 방식을 지양해야 할까요? import { type ChangeEvent, useState, useRef, useEffect } from 'react'; import { useRouter } from 'next/router'; import BoardWrite_presenter from './BoardWrite_presenter'; import { CREATE_BOARD, UPDATE_BOARD, UPLOAD_FILE } from './BoardWrite_queries'; import { useMutation, useQuery } from '@apollo/client'; import { type IBoardWrite_container_Props, type IUpdatedVariables, } from './BoardWrite_types'; import { type Address } from 'react-daum-postcode/lib/loadPostcode'; import { checkFileValidation } from '../../commons/checkFileValidation'; import { Modal, Spin } from 'antd'; import type { RcFile } from 'antd/es/upload'; import type { UploadFile } from 'antd/es/upload/interface'; import { getBase64 } from '@/src/commons/utils/utils'; import { FETCH_BOARD } from '../detail/BoardDetail_queries'; import { type IQuery } from '@/src/commons/types/generated/types'; import { Loading3QuartersOutlined } from '@ant-design/icons'; export default function BoardWrite_container( props: IBoardWrite_container_Props ) { const router = useRouter(); const boardId = router.query.boardId; if (props.isEditing && !boardId) { return ( <Spin indicator={<Loading3QuartersOutlined spin />} /> ) } const { data } = useQuery<Pick<IQuery, 'fetchBoard'>>(FETCH_BOARD, { variables: { boardId, }, }); const fetchBoard = data?.fetchBoard; if (props.isEditing && !boardId && !fetchBoard) { return ( <Spin indicator={<Loading3QuartersOutlined spin />} /> ) } const [createBoard] = useMutation(CREATE_BOARD); const [updateBoard] = useMutation(UPDATE_BOARD); const [images, setImages] = useState('youtube'); const [isOpen, setIsOpen] = useState(false); const [writerError, setWriterError] = useState(false); const [passwordError, setPasswordError] = useState(false); const [titleError, setTitleError] = useState(false); const [contentsError, setContentsError] = useState(false); const [valid, setValid] = useState(false); interface ICoreInput { [key: string]: string writer: string password: string title: string contents: string } const [coreInput, setCoreInput] = useState<ICoreInput>({ writer: fetchBoard?.writer ?? '', password: '', title: fetchBoard?.title ?? '', contents: fetchBoard?.contents ?? '' }) const [coreInputErorr, setCoreInputErorr] = useState({ writer: false, password: false, title: false, contents: false }) useEffect(() => { if (fetchBoard) { setCoreInput({ ...coreInput, writer: String(fetchBoard.writer), title: String(fetchBoard.title), contents: String(fetchBoard.contents), }) } }, [data]) const onChangeCoreInput = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => { setCoreInput({ ...coreInput, [e.currentTarget.id]: e.currentTarget.value }); setCoreInputErorr({ ...coreInputErorr, [e.currentTarget.id]: false }); const AllInputs: string[] = []; for (const prop in coreInput) { if (prop !== e.currentTarget.id) { AllInputs.push(coreInput[prop]) } else { AllInputs.push(e.currentTarget.value) } } console.log("AllInputs : " + AllInputs) if (!AllInputs.includes('' && "undefined")) { setValid(true); } else setValid(false); }; const onChangeImages = (e: ChangeEvent<HTMLInputElement>) => { setImages(e.target.value); }; const [input, setInput] = useState({ zipcode: "", address: "", addressDetail: "", youtubeUrl: "" }) const onChangeInput = (e: ChangeEvent<HTMLInputElement>) => { setInput({ ...input, [e.target.id]: e.target.value }); }; const onSubmit = async (e: { preventDefault: () => void }) => { e.preventDefault(); if (coreInput.writer === '') { setWriterError(true); } if (coreInput.password === '') { setPasswordError(true); } if (coreInput.title === '') { setTitleError(true); } if (coreInput.contents === '') { setContentsError(true); } if (coreInput.writer && coreInput.password && coreInput.title && coreInput.contents) { try { const result = await createBoard({ variables: { createBoardInput: { writer: coreInput.writer, contents: coreInput.contents, password: coreInput.password, title: coreInput.title, youtubeUrl: input.youtubeUrl, images, boardAddress: { zipcode: input.zipcode, address: input.address, addressDetail: input.addressDetail, }, }, }, }); void router.push(`/boards/${result.data.createBoard._id}`); } catch (error) { if (error instanceof Error) alert(error.message); } } }; const onUpdate = async (e: { preventDefault: () => void }) => { e.preventDefault(); const updatedVariables: IUpdatedVariables = { boardId, password: coreInput.password, updateBoardInput: { contents: coreInput.contents, title: coreInput.title, youtubeUrl: input.youtubeUrl, images, boardAddress: { zipcode: input.zipcode, address: input.address, addressDetail: input.addressDetail, }, }, }; if (!coreInput.password) { setPasswordError(true); } if (!coreInput.title) { setTitleError(true); } if (!coreInput.contents) { setContentsError(true); } if (!coreInput.password && !coreInput.title && !coreInput.contents) { try { const result = await updateBoard({ variables: updatedVariables, }); void router.push(`/boards/${result.data.updateBoard._id}`); } catch (error) { if (error instanceof Error) alert(error.message); } } }; const onToggleModal = () => { setIsOpen((prev) => !prev); }; const handleComplete = (data: Address) => { let fullAddress = data.address; let extraAddress = ''; if (data.addressType === 'R') { if (data.bname !== '') { extraAddress += data.bname; } if (data.buildingName !== '') { extraAddress += extraAddress !== '' ? `, ${data.buildingName}` : data.buildingName; } fullAddress += extraAddress !== '' ? ` (${extraAddress})` : ''; } setInput({ ...input, address: fullAddress, zipcode: data.zonecode }); onToggleModal(); }; const [uploadFile] = useMutation(UPLOAD_FILE); const [imgUrl, setImgUrl] = useState("") const fileRef = useRef<HTMLInputElement>(null) const onClickFile = () => { fileRef.current?.click() } const onChangeFile = async (e: ChangeEvent<HTMLInputElement>) => { const file = e.target.files?.[0]; const isValid = checkFileValidation(file); if (!isValid) { return } if (isValid) { try { const result = await uploadFile({ variables: { file } }) setImgUrl(result.data?.uploadFile.url) } catch (error) { if (error instanceof Error) { Modal.error({ content: error.message }) } } } } const [previewOpen, setPreviewOpen] = useState(false); const [previewImage, setPreviewImage] = useState(''); const [previewTitle, setPreviewTitle] = useState(''); const [fileList, setFileList] = useState<UploadFile[]>([]); const handleCancel = () => { setPreviewOpen(false); }; const handlePreview = async (file: UploadFile) => { if (!file.url && !file.preview) { file.preview = await getBase64(file.originFileObj as RcFile); } setPreviewImage(file.url ?? (file.preview as string)); setPreviewOpen(true); setPreviewTitle(file.url ? (file.name || file.url.substring(file.url.lastIndexOf('/') + 1)) : ""); }; return ( <BoardWrite_presenter onChangeInput={onChangeInput} onChangeCoreInput={onChangeCoreInput} onChangeImages={onChangeImages} writerError={writerError} passwordError={passwordError} titleError={titleError} contentsError={contentsError} zipcode={input.zipcode} address={input.address} onSubmit={onSubmit} onUpdate={onUpdate} valid={valid} isEditing={props.isEditing} data={data} isOpen={isOpen} handleComplete={handleComplete} onToggleModal={onToggleModal} imgUrl={imgUrl} onClickFile={onClickFile} onChangeFile={onChangeFile} fileRef={fileRef} fileList={fileList} handlePreview={handlePreview} setFileList={setFileList} previewOpen={previewOpen} previewTitle={previewTitle} handleCancel={handleCancel} previewImage={previewImage} /> ); } import { Button, Image, Modal, Upload } from 'antd'; import DaumPostcodeEmbed from 'react-daum-postcode'; import { Main, Title } from '../../../commons/styles/emotion'; import * as S from './BoardWrite_styles'; import { type IBoardWrite_presenter_Props } from './BoardWrite_types'; import type { UploadProps } from 'antd/es/upload'; import { PlusOutlined } from '@ant-design/icons'; export default function BoardWrite_presenter( props: IBoardWrite_presenter_Props ) { const valid = props.valid; const isEditing = props.isEditing; const data = props.data?.fetchBoard; const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => { props.setFileList(newFileList); }; const uploadButton = ( <div> <PlusOutlined /> <div style={{ marginTop: 8 }}>Upload</div> </div> ); return ( <Main> <S.Form> <Title>게시물 {isEditing ? '수정' : '등록'}</Title> <div className="writer"> <S.InputWrapper> <label>작성자</label> <input id="writer" onChange={props.onChangeCoreInput} type="text" placeholder="이름을 입력해주세요." defaultValue={props.data?.fetchBoard.writer ?? ""} readOnly={!!props.data?.fetchBoard.writer} /> {props.writerError && ( <p className="alert">이름을 입력해주세요.</p> )} </S.InputWrapper> <S.InputWrapper> <label>비밀번호</label> <input id="password" onChange={props.onChangeCoreInput} autoComplete="off" type="password" placeholder="비밀번호를 입력해주세요." defaultValue={``} /> {props.passwordError && ( <p className="alert">비밀번호를 입력해주세요.</p> )} </S.InputWrapper> </div> <S.InputWrapper> <label>제목</label> <input id='title' onChange={props.onChangeCoreInput} type="text" placeholder="제목을 작성해주세요." defaultValue={data?.title} /> {props.titleError && ( <p className="alert">제목을 작성해주세요.</p> )} </S.InputWrapper> <S.InputWrapper> <label>내용</label> <textarea id='contents' onChange={props.onChangeCoreInput} placeholder="내용을 작성해주세요." defaultValue={props.data?.fetchBoard.contents} /> {props.contentsError && ( <p className="alert">내용을 작성해주세요.</p> )} </S.InputWrapper> <S.InputWrapper> <label>주소</label> <div className="zipcode"> <input id="zipcode" onChange={props.onChangeInput} type="text" // placeholder="00000" readOnly value={ props.address || (props.data?.fetchBoard.boardAddress?.address ?? "") } /> <button onClick={(e) => { e.preventDefault(); props.onToggleModal(); }} > 우편번호 검색 </button> {props.isOpen && ( <Modal title={'우편번호 검색'} open={props.isOpen} onOk={props.onToggleModal} onCancel={props.onToggleModal} > <DaumPostcodeEmbed onComplete={props.handleComplete} ></DaumPostcodeEmbed> </Modal> )} </div> <input id='address' onChange={props.onChangeInput} className="address" type="text" readOnly value={props.address !== "undefined" ? props.address : ""} /> <input id='addressDetail' onChange={props.onChangeInput} type="text" defaultValue={ data?.boardAddress?.addressDetail ? data?.boardAddress?.addressDetail : '' } /> </S.InputWrapper> <S.InputWrapper> <label>유튜브</label> <input id='youtubeUrl' onChange={props.onChangeInput} type="text" placeholder="링크를 복사해주세요." defaultValue={ data?.youtubeUrl ? data?.youtubeUrl : '' } /> </S.InputWrapper> <S.InputWrapper> <label>사진업로드</label> <Button onClick={props.onClickFile}>사진 업로드</Button> <input style={{ display: "none" }} ref={props.fileRef} onChange={props.onChangeFile} type="file" /> </S.InputWrapper> {props.imgUrl && <Image src={`https://storage.googleapis.com/${props.imgUrl}`}></Image>} <S.InputWrapper> <label>사진 첨부</label> <Upload // action="https://www.mocky.io/v2/5cc8019d300000980a055e76" listType="picture-card" fileList={props.fileList} onPreview={props.handlePreview} onChange={handleChange} > {props.fileList.length >= 8 ? null : uploadButton} </Upload> <Modal open={props.previewOpen} title={props.previewTitle} footer={null} onCancel={props.handleCancel}> <img alt={props.previewTitle} style={{ width: '100%' }} src={props.previewImage} /> </Modal> </S.InputWrapper> <S.InputWrapper> <div className="radios"> <span> <input type="radio" id="youtube" name="radios" value="youtube" defaultChecked onChange={props.onChangeImages} /> <label htmlFor="youtube">유튜브</label> </span> <span> <input type="radio" id="image" name="radios" value="image" onChange={props.onChangeImages} /> <label htmlFor="image">사진</label> </span> </div> </S.InputWrapper> <S.SubmitButton onClick={isEditing ? props.onUpdate : props.onSubmit} valid={valid} disabled={!valid} > {isEditing ? '수정하기' : '등록하기'} </S.SubmitButton> </S.Form> </Main> ); }
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
Server Error Error: '@next/font' is only available in Next.js 13 and newer. 오류
이러한 오류떄문에 지금 만든 게시판등록 페이지가 실행이안됩니다 포트폴리오 01
-
해결됨만들면서 배우는 프론트엔드 DO IT 코딩 (Next.js, Typescript)
아직 못 들었는데 듣기 시작한 날부터 수강기한 시작할 수 없을까요?
개인 사정으로 결제만 해두고 강의를 하나도 듣지 못했는데,이제 시간이 조금씩 나서 듣기 시작하려고 합니다.그런데 강의 기한이 2달 조금 안되게 남아서 수강기한을 다시 설정할 수 없을까요?
-
미해결만들면서 배우는 프론트엔드 DO IT 코딩 (Next.js, Typescript)
사용하시는 zsh 테마가 뭐예요?
강의 화면에서 터미널을 보았습니다.사용하시는 쉘과 테마가 궁금합니다.감사합니다.
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
회원가입 코드 작성후, 500에러
안녕하세요 강사님! 강의 잘 듣고 있습니다!!현재 회원가입 페이지 기능생성(3)을 듣고있는데요.회원가입 요청을 보내는 과정에서 500오류가 뜹니다. 일단 로그를 확인해봤는데요. 클라이언트는 문제가 없는것 같았고, server와 db에러로그를 살펴봤습니다.server에러로그server running at http://localhost:4000 Error: connect ECONNREFUSED 127.0.0.1:5432 at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1159:16) { errno: -61, code: 'ECONNREFUSED', syscall: 'connect', address: '127.0.0.1', port: 5432 } Error: DataSource is not set for this entity. at Function.getRepository (/Users/seokjiseon/Desktop/coding/clone/reddit/server/src/repository/BaseEntity.ts:115:19) at Function.findOneBy (/Users/seokjiseon/Desktop/coding/clone/reddit/server/src/repository/BaseEntity.ts:489:21) at /Users/seokjiseon/Desktop/coding/clone/reddit/server/src/routes/auth.ts:13:34 at Generator.next (<anonymous>) at /Users/seokjiseon/Desktop/coding/clone/reddit/server/src/routes/auth.ts:8:71 at new Promise (<anonymous>) at __awaiter (/Users/seokjiseon/Desktop/coding/clone/reddit/server/src/routes/auth.ts:4:12) at register (/Users/seokjiseon/Desktop/coding/clone/reddit/server/src/routes/auth.ts:6:56) at Layer.handle [as handle_request] (/Users/seokjiseon/Desktop/coding/clone/reddit/server/node_modules/express/lib/router/layer.js:95:5) at next (/Users/seokjiseon/Desktop/coding/clone/reddit/server/node_modules/express/lib/router/route.js:144:13) POST /api/auth/register 500 52.995 ms - 10 Error: DataSource is not set for this entity.이 문구를 보고, db와 연결이 안됐다고 추측하고 db로그를 확인했습니다. db로그Attaching to postgresdocker-compose up을 입력하면, 여기서 넘어가지 않더라구요.ㅠㅠ 구글링해보니 docker-compose up -d 를 입력하면 실행로그를 자세히 볼수 있다고 해서 입력해 봤는데요. 아래 오른쪽 터미널 창에 뜨는게 무한히 반복되는 상태만 지속되고 있었습니다.. 백엔드 지식이 전무해서, docker랑 db를 전부 처음 다뤄봐서 혼자 해결하기 어려워서 질문 남깁니다ㅠㅠ혹시 어떤부분을 더 살펴봐야 할까요??ㅠㅠ
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
UI 재사용성 질문
export const Row = styled.div` display: flex; flex-direction: row; width: 100%; justify-content: space-between; padding: 0 24px; margin: 8px 0; `; <Row style={{ justifyContent: "start" }}> <InputFieldSmall style={{ marginRight: "16px" }}> <Input placeholder="07250" /> </InputFieldSmall> <ButtonBlack>우편번호 검색</ButtonBlack> </Row>안녕하세요!컴포넌트 재사용성에 관하여 질문드리고 싶은게 있습니다!1일차 게시글 작성 UI 만들기 과제를 진행하던 중 CSS 스타일을 재사용 하기 위해서 Row라는 컴포넌트를 만들었습니다.UI상 justify-content속성에 space-between 또는 flex-start 같이 약간만 변하는 부분이 존재해서 inline-stlye을 사용하였습니다.제공 해주신 레퍼런스 코드에는 inline-style을 사용하지 않으셨는데 inline-style을 사용하는 것은 좋지 않은 방식인가요?
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
Nextjs gh-pages 배포
안녕하세요~Nextjs 강의 부분까지 수업을 마쳤습니다.선생님께서 nextjs & typescript로 제작하신 블로그 부분을 gh-pages를 사용해서 배포해보려는데 디렉토링 부분이나 렌더되는 부분이 기존의 react 부분과 달라 질문 드립니다. baseurl 설정은 어디서 해야할까요?deploy 방식은 동일한 건가요?혹시 위의 질문 말고도 다른점이 있을까요?
-
해결됨Next.js 시작하기(feat. 지도 서비스 개발)
SSG 설명에서 나온 Disable cache 의 다른 렌더링방식들과 비교
안녕하세요!SSG 관련 설명해주실 때 개발자도구에서 Disable cache를 하면서static 데이터가 이미 들어와있고 etag가 여전히 그대로인 것으로 캐시와 상관 없이 해당 static 데이터가 영향을 주는 것을 확인해주셨는데요. 그렇다면 SSR, CSR에서 Disable cache 했을시 위의 현상과 다른게 있나요 ... ?SSR은 서버에서 계속 보낼테니 cache랑 상관 없을 것 같고 ... CSR도 JS 파일을 들고 있을테니 이 역시 상관 없을 것 같아서요...!혹시 CSR 특징에서 언급해주신 'JS 캐시 가능' 과 관련이 있다면 브라우저가 JS 캐시를 어떻게 활용하는지도 궁금합니다!감사합니다!
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
배포 후 로그인 인증이 안됩니다..
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 현재 강의대로 배포중인 상태입니다.회원가입도 잘 되어서 로그인도 되는데로그아웃이란 커뮤니티 생성 시 401 (Unauthorized)에러가 뜹니다.. 로컬에서는 아무런 문제 없이 잘 작동하고 있습니다.아무리 찾아봐도 어떤 문제가 있는지를 모르겠습니다 ㅠㅠ
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
searchbar 포트폴리오 리뷰 질문
searchbar 포트폴리오 리뷰에서 props로 searchbar 컴포넌트에 refechBoardsComment넘겨서 searchbar 컴포넌트에서 refechBoardsComment이용하여 페이지네이션을 수정없이 lastpage를변경할 수 있는데const { data: dataBoardsCount, refetch: refechBoardsCount } = useQuery<Pick<IQuery, "fetchBoardsCount">,IQueryFetchBoardsCountArgs>(FETCH_BOARDSCOUNT,{variables:{search:keyword}}); 이렇게 FETCH_BOARDSCOUNT에 variables 값의 search를 keyword(검색어)로 주어도 똑같이 작동하는데 이 방법이 refechBoardsComment props로 넘겨줄 필요없어 간단한거 같은데 refechBoardsComment이용한 것과 같은거 맞나요? 아님 refechBoardsComment를 이용한 것과 차이가 있는 건가요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
section 04 퀴즈 질문입니다 ㅠ
삭제하기 버튼을 눌럿을때 이런 에러가 뜨는데 이유를 모르겠습니다 ㅜㅠ
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
graphql 관련 질문이 있습니다.
안녕하세요 수업 내용 중, graphql 실습 관련하여 궁금한 것이 있습니다. 실습 과정에서 createProduct API에 파라미터 값을 저장해서 보내려 하는 과정에서 mutation을 구성할 때createProductInput 이라는 부분은 REST API의 다중 JSON 방식으로 보내는 것으로 해석하면 될까요?그런데 해당 데이터를 fetchProduct로 조회 시다중 JSON과 같은 그림이 아닌, 그냥 같은 한 덩어리로 넘어오는데 왜 저장할 때는 다중 JSON과 같은 방식으로 넣고 조회 시에는 그냥 뭉쳐져서 조회 되는지 차이가 궁금합니다. (그럼 굳이 CREATE 시 다중 JSON과 같은 방식으로 넣는 이유가 궁금합니다)그리고 중간에 createProductInput 을 사용하는 이유에 대해서 오해를 방지하기 위함이라고 말씀해주셨는데 키 값도 있는데 왜 오해를 불러 일으킨다는 것인지 잘 이해를 못했습니다.질문 요약첫 사진의 createProductInput 부분이 REST API의 다중 JSON 같은 방식이라고 보면 될까요?createProduct로 값을 넣을 때는 이중 JSON과 같은 방식으로 파라미터를 넣고 API를 넘겨줬는데 데이터를 조회하면 그냥 1차원 JSON으로 넘어오는데 그럼 왜 굳이 createProduct 에서 이중 JSON 방식으로 구성해서 넣는 것인지 궁금합니다. createProduct에서 createProductInput로 한 번 더 감싸는 자세한 이유 (수업 중간에 number라는 키 값으로 보이는 것도 있는데 오해를 불러 일으킬 수도 있다는 말씀에서 왜 오해인지 자세히 이해를 못함)입니다. 감사합니다.
-
해결됨따라하며 배우는 리액트 A-Z[19버전 반영]
맥용, prettier 단축키
안녕하세요vscode에서 Prettier 설치를 했는데shift + option + f단축키가 먹히질 않네요ㅠ 왜 그런 건지 알 수 있을까요..?
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
TypeORM 에러 및 middleware 설치 이후 cors 에러 문의드립니다.
안녕하세요, 강사님!강의 듣던 도중 해결하지 못한 에러가 있어 조언해주실 수 있으신지 문의드립니다. 1 TypeORM에서 다음과 같은 에러가 뜹니다.Server running at http://localhost:4000 QueryFailedError: tables can have at most 1600 columns at PostgresQueryRunner.query (생략) { query: 'ALTER TABLE "posts" ADD "title" character varying NOT NULL', parameters: undefined, driverError: error: tables can have at most 1600 columns at Parser.parseErrorMessage (생략) { length: 100, severity: 'ERROR', code: '54011', detail: undefined, hint: undefined, position: undefined, internalPosition: undefined, internalQuery: undefined, where: undefined, schema: undefined, table: undefined, column: undefined, dataType: undefined, constraint: undefined, file: 'tablecmds.c', line: '6819', routine: 'ATExecAddColumn' }, length: 100, severity: 'ERROR', code: '54011', detail: undefined, hint: undefined, position: undefined, internalPosition: undefined, internalQuery: undefined, where: undefined, schema: undefined, table: undefined, column: undefined, dataType: undefined, constraint: undefined, file: 'tablecmds.c', line: '6819', routine: 'ATExecAddColumn' } <== 이 부분이 계속 반복됩니다 (반복적으로 테이블이 생성되는 듯)stackoverflow를 찾아보니 oneToMany relation이 문제가 된다는 글을 봤는데... 제가 백앤드쪽 지식이 전무하다보니, oneToMany 데코레이터로 설정된 Entity를 어떻게 수정해야하는건지 잘 모르겠고, 강사님 코드와 동일하게 작성한 것 같은데 뭐가 문젠지 잘 모르겠습니다.특히나 아래 코드 중,{ length: 100, severity: 'ERROR', .... }이 부분이 반복적으로 로그에 찍히는데 어떻게 해결해야할지 잘 모르겠습니다.이 글을 보니, nomarlization을 진행하라는데 이게 맞는 솔루션인가요?백앤드 해보고 싶어서 아는 것 없이 무작정 따라하는 중인데, 지식이 부족해서 제대로 된 해결방법이 뭔지 알 수가 없네요.. 2middleware 설치 전까지는 회원가입 기능이 잘 되었었는데, middleware 설치 이후로는, 로컬호스트 3000에서 cors 에러가 뜹니다. (아래 이미지 첨부)로그인, 회원가입 기능 어떤것도 되지 않는 상태이고, token도 생성되지 않습니다.일단 계속해서 강의를 듣고 있는데 에러 해결이 안되어 더이상 진도를 나갈 수가 없어서 문의남깁니다 ㅠㅠAccess to XMLHttpRequest at 'http://localhost:4000/api/auth/me' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. { "message": "Network Error", "name": "AxiosError", "stack": "AxiosError: Network Error\n at XMLHttpRequest.handleError (webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:168:14)", "config": { "transitional": { "silentJSONParsing": true, "forcedJSONParsing": true, "clarifyTimeoutError": false }, "adapter": [ "xhr", "http" ], "transformRequest": [ null ], "transformResponse": [ null ], "timeout": 0, "xsrfCookieName": "XSRF-TOKEN", "xsrfHeaderName": "X-XSRF-TOKEN", "maxContentLength": -1, "maxBodyLength": -1, "env": {}, "headers": { "Accept": "application/json, text/plain, /" }, "baseURL": "http://localhost:4000/api", "withCredentials": true, "method": "get", "url": "/auth/me" }, "code": "ERR_NETWORK", "status": null } 나름대로 검색도 해보고, node_modules 싹 날리고 재설치해봤으나.. ㅠㅠ 답변 기다리겠습니다 감사합니다
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
제너레이터 함수 안 yield 구문 실행에대해 질문드립니다..
function* test() { yield 1; yield 2;}===============const gen = test()===============gen.next(){ "value": 1, "done": false}보통 제너레이터 함수를 설명할때, 개발자 도구에서 이런식으로 설명을 많이 하는것같은데...설명만 보면 yield 구문실행을 위해선, next() 라는 함수를 사용해야된다는건 알겠습니다..근데 실제코드에서는 next() 함수를 실행하지않는데, 어떻게 yield 구문들이 실행되는지 이해가 안됩니다..
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
Wsl mysql 질문
오늘 하루 mysql 설정하는거때문에 다 날려먹으면서 혼자서 해보고있는데 우여곡절 끝에 WSL에 mysql까지 실행 성공시켜서 그안에 react-nodebird database가 있는건 확인했는데 윈도우에 깐 mysql-workbench랑 연동을 못하고있는데 크게 상관 없을까요 제로초쌤..?
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
react-netflix-clone 오류 문의
안녕하세요!react-netflix-clone의 메인 페이지에서 발생한 오류에 대해 문의 드립니다.문의1) key={movies.id} 에 대해 "list should have a unique "key" prop" 오류가 발생합니다.Row.js ... <div id={id} className='row__posters'> {movies.map((movie) => ( <SwiperSlide> <img key={movie.id} style={{ padding: "25px 0" }} className={`row__poster ${isLargeRow && "row__posterLarge"}`} src={`https://image.tmdb.org/t/p/original/${ isLargeRow ? movie.poster_path : movie.backdrop_path }`} alt={movie.name} onClick={() => { imageClickHandler(movie) }} /> </SwiperSlide> ))} </div>MainPage.js 에서 Row 컴포넌트를 하나만 정의해도 동일한 오류가 발생합니다. 문의2) useEffect eslint warning이 안나게 하려면 어떻게 해야 하나요?useEffect(() => { fetchMovieData(); }, []); ==> warning WARNING in [eslint] src/components/Row.js Line 24:8: React Hook useEffect has a missing dependency: 'fetchMovieData'. Either include it or remove the dependency array react-hooks/exhaustive-deps 문의3) autoprefixer warning이 안나게 하려면 어떻게 해야 하나요?warningWARNING 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 insteadBanner.css (제공 소스 그대로 적용함).banner { color: white; object-fit: contain; height: 448px; } @media (min-width: 1500px) { .banner { position: relative; height: 600px; } .banner--fadeBottom { position: absolute; bottom: 0; width: 100%; height: 40rem; } } @media (max-width: 768px) { .banner__contents { width: min-content !important; padding-left: 2.3rem; margin-left: 0px !important; } .banner__description { font-size: 0.8rem !important; width: auto !important; } .info { text-align: start; padding-right: 1.2rem; } .space { margin-left: 6px; } .banner__button { font-size: 0.8rem !important; border-radius: 4px !important; } } .banner__contents { margin-left: 40px; padding-top: 140px; height: 190px; } .banner__title { font-size: 3rem; font-weight: 800; padding-bottom: 0.5rem; } .banner__description { width: 45rem; line-height: 1.3; padding-top: 1rem; font-weight: 500; font-size: 1rem; max-width: 400px; height: 80px; } .banner--fadeBottom { height: 7.4rem; background-image: linear-gradient( 180deg, transparent, rgba(37, 37, 37, 0.61), #111 ); } .banner__buttons { display: flex; flex-direction: row; } .banner__button { display: flex; flex-direction: row; justify-content: start; align-items: center; cursor: pointer; outline: none; border: none; font-size: 1rem; font-weight: 700; border-radius: 0.2vw; padding: 0.4rem 1.8rem 0.4rem 1rem; margin-right: 1rem; } .banner__button:hover { color: #000; background-color: rgba(170, 170, 170, 0.9); transition: all 0.2s; } .play { background-color: white; color: black; } .info { background-color: rgba(109, 109, 110, 0.7); color: white; } .info:hover { background-color: rgb(74, 74, 74); color: white; } .space { margin-left: 4px; }
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
_app.tsx 에러
_app.tsx 로 바꾸고나서 <Component/>에서 에러가 나는데 어떻게 해야하나요...?