묻고 답해요
161만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결MERN STACK 커뮤니티 : 시작부터 배포까지 알려주는 React
빌드하지 않고 테스트가 가능한가요?
'Read(1): 게시글 불러오기' 부분 수강중에 있습니다.강사님께서는 프론트부분 코드를 수정하시고도 npm run build 명령어 입력 없이 즉, 빌드 없이 바로 브라우저에서 테스트가 가능하신 것 같은데 어떻게 하신 건가요?저 같은 경우는 구름 ide라는 클라우드 서비스로 visual studio code를 이용중이며3000번 포트에서는 react를, 5000번 포트에서는 node를 사용중에 있습니다. 그래서 코드 한번 수정 후 테스트 해볼 때터미널에서 client폴더로 이동 -> npm run builid -> server폴더로 이동 -> nodemon index.js이후에 브라우저 들어가서 코드 바꾼 것 잘 적용 되었는지 확인중에 있습니다. 그런데 리액트 코드가 길어지면 길어질수록 빌드하는데 시간이 너무 오래 걸리네요 ㅠㅠ 강사님처럼 빌드하지 않고 바로 확인할 수 있는 방법이 있는지 궁금합니다.추가로 판다코딩님 깃헙 링크좀 부탁드립니다!
-
해결됨따라하며 배우는 리액트 A-Z[19버전 반영]
마이너스 버튼 관련 질문
안녕하세요아래와 같이 코드를 작성할 경우, 0 으로 입력하면 에러 메세지가 보여집니다.반대로 플러스 버튼과 동일하게 1로 하면 에러 없이 제대로 작동이 됩니다.왜 0으로 하면 에러가 발생하는 걸까요?test('when the - button is pressed, the counter change to 0', () => { render(<App />); const buttonElement = screen.getByTestId("minus-button"); // click plus button fireEvent.click(buttonElement); // 카운터가 1에서 -1로 되서 0이 된다. const counterElement = screen.getByTestId("counter"); expect(counterElement).toHaveTextContent(0); })
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
index.js 오류
post/user/등 강좌 되돌려 보면서 틀린 곳이 있나 확인했는데,어디서 부터 고쳐야 될지 모르겠습니다. index.jsimport React from 'react'; import { useSelector } from 'react-redux'; import PostForm from '../components/PostForm'; import PostCard from '../components/PostCard'; import AppLayout from '../components/AppLayout' const Home = () => { const { isLoggedIn } = useSelector((state) => state.user); const { mainPosts } = useSelector((state) => state.post); return ( <AppLayout> {isLoggedIn && <PostForm/>} {mainPosts.map((post)=><PostCard key={post.id} post={post}/>)} </AppLayout> ); } export default Home;
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
8:24분경 코드 오류나서 수정하셨는데!
8분 20초경 오류나서 코드를 수정하셨는데,case ADD_POST_TO_ME: return { ...state, me: { ...state.me, // 이부분 왜 추가한건가요? Posts: [{ id: action.data }, ...state.me.Posts], }, };코드 주석부분 왜 추가하신건가요..?const dummyUser = (data) => ({ ...data, nickname: "wewewe", id: 1, Posts: [{ id: 1 }], Followings: [{ nickname: "we1" }, { nickname: "we2" }, { nickname: "we3" }], Followers: [{ nickname: "we1" }, { nickname: "we2" }, { nickname: "we3" }], });dummy데이터 구조를 보면Posts를 제외한 nickname, id, Followings 등 변하지 않는 데이터들의 불변성을 유지하기 위해서 추가한것이 맞는건가요?!
-
미해결비전공자를 위한 진짜 입문 올인원 개발 부트캠프
error:03000086:digital envelope routines::initialization error axios오류
안녕하세요 axios 코드 실행 하면 아래 사진과 같이 오류가 뜹니다.
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
ADD_COMMENT_SUCCESS 새로운 post에서만 작동 안 하는 문제
안녕하세요 제로초 님,redux saga immer, faker 까지만 들었구요, 백엔드는 안 만들었고요.faker가 문제가 있다길래,import { faker } from '@faker-js/faker';이거를 대신해서 설치해서 했는데, 이거의 문제는 아닌거 같고요. ADD_COMMENT_SUCCESS가기존의 post에서는 작동을 하는데, 새로운 post에서만 작동 안 하는 문제가 있습니다. 새로운 post.id가 동작을 안 하나 싶어const post = draft.mainPosts.find((post)=> { console.log(post.id == action.data.postId); return post.id == action.data.postId; });를 해봤는데 역시 true가 나옵니다.아래는 브라우저 결과 사진들 입니다.로그인 안 했을 때,로그인 하고 기존의 post에 comment를 달았을 때 -> 정상적으로 동작 함. 로그인 하고 새로운 post을 하나 추가 -> 정상적으로 동작 함. username이 바뀌는 건 faker를 썼고, userId만 그래도 컴포넌트에서 받아서 써서 지금 ADD_POST_TO_ME 동작해서 1에서 2로 바뀌었구요.그러나새로운 post에 comment를 달았을 때 -> 콘솔로그가 true가 나옴에도 동작을 하지 않음. 기존의 post에도 comment가 안 달리는 거면 제가 실수를 한게 분명한데, 새로운 post에만 동작을 안 하는게 이상합니다.ADD_COMMENT_REQUEST를 보냈을 때에도, 갑자기 mainPosts가 초기화 되거나 그런 것도 아니었습니다. 만약 그랬다면 콘솔로그가 false가 나왔어야 합니다. 감사합니다!
-
미해결처음 만난 리액트(React)
Chapter12 Calculaotr.jsx 질문
안녕하세요, 소플님. Chapter12 Calculaotr.jsx 파일에 있는섭씨, 화씨 온도 변환 코드와관련해서 문의드리고 싶은 부분이 있어 글을 남깁니다. 만약 사용자가 섭씨 온도 입력한에 섭씨 온도를 입력했다고 했을 때온도는 temperature 변수에 저장되고, 섭씨 온도를 입력했기에celsius란 변수에 저장됩니다. 또한 scale은 c 입니다. 사용자가 섭씨 온도를 입력했으니 화씨 온도로 바꿔줘야 할 차례인데이 부분부터 잘 이해가 가지 않습니다. const celsius = scale === "f" ? tryConvert(temperature, toCelsius) : temperature; 저는 위의 코드를 섭씨 온도를 화씨 온도로 바꿔주는 부분으로 이해했습니다.하지만 그러기 위해선 scale === f 로 두고, tryConvert(temperature, toCelsius) 로 두는 게 아닌 const celsius = scale === "c" ? tryConvert(temperature, toFahrenheit) : temperature;위의 코드처럼 scale을 c로 두고tryConvert(temperature, toFahrenheit) 로 바꿔줘야사용자가 입력한 섭씨 온도를 화씨 온도로 바꿔줘.가 되는 걸로 이해했습니다. scale을 c로 둔 이유는 사용자가 섭씨 온도를 입력하면온도는 temperature 변수, 그리고 celsius 변수에 저장되며celsisus 변수에 저장되면서 동시에 위의 코드에 의해 scale은 c가 되기에scale을 c로 뒀습니다. const celsius = scale === "c" ? tryConvert(temperature, toFahrenheit) : temperature; 그래서 위에처럼 코드를 작성해야섭씨 온도를 화씨 온도로 바꿔주는 거라고 생각했습니다. 혹시 제가 어떤 부분에서 잘못 생각하고 있는지 알 수 있을까요?
-
미해결[리뉴얼] 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 /> 경고문이 뜨지 않는 사진도 첨부했습니다.
-
미해결비전공자를 위한 진짜 입문 올인원 개발 부트캠프
React-router-dom 흰 화면 오류
React-router-dom 5.2.0 으로 다운그레이드 하였으나,흰 화면으로 나타납니다. 에러가 있는 것 같아요...!커뮤니티를 보고 혼자 해결해 보려고 하였으나... 커뮤니티에 있는 방법들로 해결이 안되어서 여쭤봅니다.도와주세요..! ㅠㅠ
-
미해결웹 게임을 만들며 배우는 React에 TypeScript 적용하기
undefined 처리
강의에서 computerChoice의 리턴타입에 undefined가 추가되어있는 문제 해결하실때 if() throw new Error(); 사용해서 처리하거나 느낌표(!) 사용하신다했는데 if() throw new Error();로 어떻게 처리하신다는건지 알 수 있을까요? 어떻게 해봐도 해결이 안되네요. ㅠㅠ const rspCoords = { 바위: '0', 가위: '-142px', 보: '-284px', } as const; const scores = { 가위: 1, 바위: 0, 보: -1, } as const; type imgCoords = typeof rspCoords[keyof typeof rspCoords]; const computerChoice = (imgCoords: imgCoords) => { return (Object.keys(rspCoords) as ['바위', '가위', '보']).find(function (v) { return rspCoords[v] === imgCoords; }); };
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
수정 페이지 마운트 직후, 온체인지 핸들러가 인풋 값을 ""으로 인식하여, 인풋 값를 지웠을 경우, 온체인지 핸들러가 값의 변동을 인식하지 못하는 문제가 있습니다.
안녕하세요 강의 잘 보고있습니다.수정 페이지 마운트 직후, 온체인지 핸들러가 인풋 값을 ""으로 인식하고, 인풋 값를 지웠을 경우, 온체인지 핸들러가 값의 변동을 인식하지 못하는 문제가 있습니다.즉, 수정 페이지의 각 인풋 디폴트 값들에 데이터가 불러와진 후, 값을 입력하는 것이 아니라 삭제할 경우에 값의 변동을 온체인지 핸들러가 인식하지 못하여 발생합니다.따라서, 인풋의 온체인지 핸들러를 통해 인풋 값들이 비어있는지 확인하는 유효성 검사에 작은 오류가 있습니다. 수정페이지 마운트 직후 데이터를 불러온 뒤, 값이 인풋에 입력된 후, 온체인지핸들러가 변동을 인식하게 할 수 있을까요? 혹시 비슷한 인풋 값들을 객체에 묶어 저장하는 방식을 지양해야 할까요? 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
-
미해결Slack 클론 코딩[실시간 채팅 with React]
key prop 에러
Workspace에서 {channelData?.map((v) => ( <div>{v.name}</div> ))}콘솔에서 이 부분 때문에 key prop 에러가 나는 것 같은데 나중에 ChannelList로 바꿀꺼라서 신경 쓰지 않아도 되는 부분인가요??
-
미해결웹 게임을 만들며 배우는 React에 TypeScript 적용하기
compilerOptions lib 관련
강의에서 lib 옵션 배열에 es5, es2015, es2016, es2017 등 모두 적어두면 좋다고 말씀해주셨는데 스펙에 추가된 문법이나 이런것들을 사용하기 위해서 그렇게 말씀해주신걸로 아는데 다른것들은 작성하지 않고 아래와 같이"lib": ["ESNext", "DOM"],또는 최신 ES2022 작성하면 그 이하의 스펙?들은 작성할 필요 없는거 아닌가요? 그래도 모두 작성해야 하는건가요?
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(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를 전부 처음 다뤄봐서 혼자 해결하기 어려워서 질문 남깁니다ㅠㅠ혹시 어떤부분을 더 살펴봐야 할까요??ㅠㅠ
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
section 02 quiz 네번째 관련 질문입니다!
Int cannot represent non-integer value에러 404가 발생하면 네트워크 콘솔 창에서 해당 오류가 계속 발생한다고 뜹니다. 아마 가격을 제대로 입력받지 못해서 뜨는 오류같은데 어떻게 해결하는지 모르겠습니다 ㅠimport { gql, useMutation } from '@apollo/client' import { Fragment, useState } from 'react' const CREATE_PRODUCT = gql` mutation createProduct($seller: String, $createProductInput: CreateProductInput!){ createProduct(seller: $seller, createProductInput:$createProductInput){ _id number message } } ` export default function Graphql_Mutation2(){ const [seller, setSeller] = useState('') const [name, setName] = useState('') const [detail, setDetail] = useState('') const [price, setPrice] = useState(0) const [myFunction] = useMutation(CREATE_PRODUCT) const onClickSubmit = async () => { const result = await myFunction({ variables:{ seller:seller, createProductInput:{ name:name, detail:detail, price:price } } }) console.log(result) console.log(seller, name, detail, price) alert(result.data.createProduct.message) } const onChangeSeller = (e) => { setSeller(e.target.value) } const onChangeName = (e) => { setName(e.target.value) } const onChangeDetail = (e) => { setDetail(e.target.value) } const onChangePrice = (e) => { parseInt(setPrice(e.target.value)) } return( <Fragment> 판매자: <input type='text' onChange={onChangeSeller} /><br /> 판매 제품: <input type='text' onChange={onChangeName} /><br /> 간략한 소개: <input type='text' onChange={onChangeDetail} /><br /> 가격: <input type='number' onChange={onChangePrice} /><br /> <button onClick={onClickSubmit}>GRAPHQL-API(동기) 요청하기</button> </Fragment> ) }
-
미해결Slack 클론 코딩[실시간 채팅 with React]
'Date' 형식은 'ReactNode' 형식에 할당할 수 없습니다.
제로초님, 코드를 따라치는 중에'Date' 형식은 'ReactNode' 형식에 할당할 수 없습니다.라는 오류 메세지가 떴습니다. 그래서 index.d.ts에 들어가서type ReactNode에 Date 타입을 적어주었는데, 오류 메세지는 사라졌지만, 화면에 에러는 그대로 있습니다. 이 에러는 어떻게 해결하나요?? typescript는 v 18입니다!
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
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 방식은 동일한 건가요?혹시 위의 질문 말고도 다른점이 있을까요?
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
배포 후 로그인 인증이 안됩니다..
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 현재 강의대로 배포중인 상태입니다.회원가입도 잘 되어서 로그인도 되는데로그아웃이란 커뮤니티 생성 시 401 (Unauthorized)에러가 뜹니다.. 로컬에서는 아무런 문제 없이 잘 작동하고 있습니다.아무리 찾아봐도 어떤 문제가 있는지를 모르겠습니다 ㅠㅠ