묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
게시글 등록,삭제시 실시간 반영되지 않습니다.
안녕하세요 제로초님 강의듣고 리덕스, 사가 대신 툴킷과 내장 썽크를 사용해서 다시 만들어보는 중인데 게시글 등록시 글은 정상적으로 등록이 되는데 게시글 갯수가 실시간으로 바뀌지 않고 새로고침 해야 반영이 됩니다. 삭제할때도 정상적으로 삭제는 되는데 새로고침해야 삭제된 결과가 반영이 됩니다. 백엔드 부분은 강의와 같이 js로 작성했고 게시글 작성 툴킷은 다음과 같이 코드작성했습니다. // toolkit/post.ts export const initialState: PostState = { // 기본값 mainPosts: [], imagePaths: [], postAdded: false, // 게시글 로딩 loadPostLoading: false, loadPostDone: false, loadPostError: null, // 추가 로딩 hasMorePosts: false, // 게시글 작성 addPostLoading: false, addPostDone: false, addPostError: null, // 게시글 삭제 removePostLoading: false, removePostDone: false, removePostError: null, export const addPostAction = createAsyncThunk( 'post/addPost', async (data: FormData) => { const response = await axios.post('/post', data); return response.data; } ); export const removePostAction = createAsyncThunk( '/post/delete', async (data: number) => { const response = await axios.delete(`/post/${data}`); return response.data; } ); extraReducers: (builder) => { builder // 게시글 추가 .addCase(addPostAction.pending, (draft) => { draft.addPostLoading = true; draft.addPostDone = false; draft.addPostError = null; }) .addCase(addPostAction.fulfilled, (draft, action) => { draft.addPostLoading = false; draft.addPostDone = true; draft.mainPosts.unshift(action.payload); }) .addCase(addPostAction.rejected, (draft, action) => { draft.addPostLoading = false; draft.addPostError = action.error.message; }) // 게시글 삭제 .addCase(removePostAction.pending, (draft) => { draft.removePostLoading = true; draft.removePostDone = false; draft.removePostError = null; }) .addCase(removePostAction.fulfilled, (draft, action) => { draft.removePostLoading = false; draft.removePostDone = true; draft.mainPosts = draft.mainPosts.filter( (v) => v.id !== action.payload ); }) .addCase(removePostAction.rejected, (draft, action) => { draft.removePostLoading = false; draft.removePostError = action.error.message; }) 이해가 안가는 부분이 post에서 게시글 삭제, 입력등의 작업을 하고 user에서 회원가입,로그인,로그아웃, 팔로우 등의 작업을 하게 나눠놨는데 게시글 입력할때 mainPosts의 값이 추가될때마다 그 값이 컴포넌트에서 불러와져서 화면의 게시글 갯수 부분이 바뀌는건 이해가 가는데 // pages/index.ts const Home = () => { const { mainPosts, hasMorePosts, loadPostLoading } = useSelector( (state: RootState) => state.post ); {me && <PostForm />} {mainPosts.map((post) => ( <PostCard key={post.id} post={post} /> ))} 이 부분에서/component/UserProfile.tsx const UserProfile = () => { const { me, logOutLoading } = useSelector((state: RootState) => state.user); return ( <> <Card actions={[ <div key='twit'> 짹짹 <br /> {me?.Posts.length} </div>, <div key='follower'> 팔로워 <br /> {me?.Followings.length} </div>, <div key='following'> 팔로잉 <br /> {me?.Followers.length} </div>, ]} > me는 툴킷의 user.ts 의 me를 참조하는거 아닌가요? 게시글 입력,삭제시 post.ts를 통해 post.ts의 mainPosts 값이 바뀌는데 user.ts를 참조하는 컴포넌트에서 me.Posts.length 값이 바뀌는 부분이 잘 이해가 가질 않습니다. 그리고 댓글 삭제기능을 추가하고 싶은데요. //pages/index.ts const { mainPosts, hasMorePosts, loadPostLoading } = useSelector( (state: RootState) => state.post ); {mainPosts.map((post) => ( <PostCard key={post.id} post={post} /> ))} //component/PostCard.tsx const { removePostLoading } = useSelector((state: RootState) => state.post); const onRemovePost = useCallback(() => { dispatch(removePostAction(post.id)); }, []); // post.ts export const removePostAction = createAsyncThunk( '/post/delete', async (data: number) => { const response = await axios.delete(`/post/${data}`); return response.data; } ); .addCase(removePostAction.fulfilled, (draft, action) => { draft.removePostLoading = false; draft.removePostDone = true; draft.mainPosts = draft.mainPosts.filter( (v) => v.id !== action.payload ); }) //back/routes/post router.delete('/:postId', isLoggedIn, async (req, res, next) => { try { await Post.destroy({ where: { id: req.params.postId, UserId: req.user.id }, }); res.status(200).json({ PostId: parseInt(req.params.postId, 10) }); } catch (err) { console.error(err); next(err); } }); 게시글을 삭제할때는 post.id로 해당하는 글의 id를 바로 보내서 삭제할수 있는건 이해가 가는데 comment의 경우 [{댓글1}, {댓글2}] 형식으로 각 댓글의 값이 들어있어서 이부분을 어떻게 해야할지 감이 잡히지 않습니다.
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
Incorrect use of <label for=FORM_ELEMENT> 오류 발생했을 때 Input에 name이 아닌 id 값을 주면 해결되는 이유가 궁금합니다!
안녕하세요! React로 NodeBird SNS 만들기섹션1 로그인 폼 만들기까지 수강한 학생입니다!사전에 next 9버전, antd 4버전을 설치하였습니다.import { Form, Input, Button } from 'antd';발생한 에러는 아래와 같습니다.콘솔에 오류가 뜨지만 화면 자체는 정상적으로 뜹니다.에러 메시지를 번역해보니 아래와 같았습니다.(오류 추정 코드이며, 버튼 코드는 아래에선 생략했습니다.)return ( <Form> <div> <label htmlFor="user-id">아이디</label> <br /> <Input name="user-id" value={id} onChange={onChangeId} required /> </div> <div> <label htmlFor="user-password">비밀번호</label> <br /> <Input name="user-password" type="password" value={password} onChange={onChangePassword} required /> </div> </Form> );에러 메시지를 확인하고 문제가 LoginForm.js 파일에서 발생한 것이라 추측했고,LoginForm의 return에 있는 Input name 속성을 id로 변경하니 콘솔 오류가 사라졌습니다.왜 해결된 것인지 이유가 궁금합니다!return ( <Form> <div> <label htmlFor="user-id">아이디</label> <br /> <Input id="user-id" value={id} onChange={onChangeId} required /> </div> <div> <label htmlFor="user-password">비밀번호</label> <br /> <Input id="user-password" type="password" value={password} onChange={onChangePassword} required /> </div> </Form> );
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
accessToken 저장 관련 질문
안녕하세요! accessToken 저장 관련하여 궁금한 점이 생겨 질문드립니다.로그인의 결과로 accessToken을 받아오고 이것을 보안 문제를 해결하고자 로컬/세션 스토리지가 아닌 변수(recoil state)에 저장하셨고 이를 로그인한 사람의 정보를 요청하기 위해 쿠키를 통해 headers에 연동 시키셨는데, 이러면 변수에 저장한 값을 어쨌든 headers의 쿠키에서 확인할 수 있게 되어 글로벌 변수에 저장한 의미가 없어진 것 아닐까 하는 생각이 들어서 질문드리게 되었습니다.항상 좋은 강의 감사드립니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
회원가입과제
안녕하세요. 회원가입 과제를 하려고 하는데너무 막막해서요...모양만 똑같이 만들면 되는 건가요?아니면 실제로 입력이 되는 형식대로 만들어야 하는 건가요?
-
해결됨따라하며 배우는 리액트 A-Z[19버전 반영]
NestJS 13에서의 컴포넌트 관리
안녕하세요! NextJS 13 강의를 듣는 과정에서 궁금증이 생겨 질문 드립니다.기존의 React 같은 경우에는 컴포넌트에 path를 지정하여 라우팅하는 방식으로 코드를 작성해나갔었던 것 같은데요,NextJS의 경우 about 페이지를 만들기 위해 about.tsx를 작성함으로써 라우팅을 구현하고, NextJS 13의 경우 디렉토리를 path 구조로 작성하여 라우팅을 구현하는 것으로 이해했습니다.React에서는 컴포넌트에 일일이 라우팅 path를 정해주기 때문에, 재사용 가능한 컴포넌트로 독립적으로 사용할 수 있었던 것 같은데 NextJS의 경우 재사용 컴포넌트를 어떻게 관리하는지 궁금하여 질문 드립니다.또한 리액트 version 18에서 Suspense를 통한 서버사이드렌더링이 SEO에 영향을 미치는지, 혹시나 SEO를 개선할 수 있다면 NextJS를 사용하지 않고 React 만으로 최적화된 앱을 만들 수 있는지 추가적으로 질문 드립니다.좋은 강의 덕에 열심히 듣고 있습니다. 질문 읽어주셔서 감사합니다!
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
섹션 36 antd icon 임포트 에러
안녕하세요.antd 임포트할때 이런 에러가 발생했는데요.이전 커뮤니티 글을 확인해서선생님이 말씀해주신 강의용 버전으로 바꾸고yarn.lock과 노드모듈즈를 다시 지운다음yarn install했는데도 아직도 저렇게 에러가 나와서요ㅠㅠ뭐가 문제일까요?yarn dev해보니 아이콘은 잘 나와요
-
해결됨Next.js 시작하기(feat. 지도 서비스 개발)
a tag 질문 !
안녕하세요 !강의 중에 a tag를 감싸고 있는 컴포넌트를 만들경우라고 하셨는데 useRouter나 Link를 쓰게 되면 a tag를 굳이 안써도 되지 않을까 생각하는데 그럼에도 불구하고 a tag를 쓰는 경우가 있을까요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
린터와 포맷터 강의 중 inport부분 파싱 에러
강사님 설치하는것도 잘 따라했는데강사님은 import부분에 오류가 안뜨는데 저는 import부분에서 이런 오류가 뜨더라고요. tsconfig에서 뭐가 잘못됐단건지 모르겠어요ㅠ
-
해결됨Next.js 시작하기(feat. 지도 서비스 개발)
8분 20초 배포 관련
안녕하세요!마지막에 8:20에 나오는 설명대로 commit을 나누어서 진행하고 push and build를 하였는데 아래와 같이 error가 발생하고 있습니다. 어떤 부분이 문제인지 궁금합니다Error occurred prerendering page "/". Read more: https://nextjs.org/docs/messages/prerender-error SyntaxError: Unexpected token < in JSON at position 0 Error: Export encountered errors on following paths:/ 아래에 코드로 build하면 정상적으로 동작합니다..const stores = (await import('../public/stores.json')).default
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
Immer 적용시 에러 문의드립니다.
안녕하세요. React Immer 적용시 나타나는 에러인데확인한번 부탁드려도 될까요?Immer 적용 전까지 코드는 잘 돌아갔는데, 에러 추적이 힘드네요. 웹 팩 환경설정 문제일까요? immer module은 잘 설치되어 있습니다. 에러내용소스코드front/reducers/user.jsimport produce from 'immer'; export const initialState = { logInLoading : false, // 로그인 시도중 logInDone : false, loginError : null, logOutLoading : false, // 로그아웃 시도중 logOutDone : false, logOutError : null, signUpLoading : false, // 회원가입 시도중 signUpDone : false, signUpFailure : null, changeNicknameLoading : false, // 닉네임 변경 시도중 changeNicknameDone : false, changeNicknameFailure : null, me : null, signUpData : {}, loginData : {}, }; const dummyUser = (data) => ({ ...data, nickname : '제로초', id : 1, Posts : [{ id : 1}], Followings : [{nickname : 'AAA'}, {nickname : 'BBB'}, {nickname : 'CCC'}], Followers : [{nickname : 'AAA'}, {nickname : 'BBB'}, {nickname : 'CCC'}], }); export const LOG_IN_REQUEST = 'LOG_IN_REQUEST'; // 액션의 이름 export const LOG_IN_SUCCESS = 'LOG_IN_SUCCESS'; export const LOG_IN_FAILURE = 'LOG_IN_FAILURE'; export const LOG_OUT_REQUEST = 'LOG_OUT_REQUEST'; // 액션의 이름 export const LOG_OUT_SUCCESS = 'LOG_OUT_SUCCESS'; export const LOG_OUT_FAILURE = 'LOG_OUT_FAILURE'; export const SIGN_UP_REQUEST = 'SIGN_UP_REQUEST'; export const SIGN_UP_SUCCESS = 'SIGN_UP_SUCCESS'; export const SIGN_UP_FAILURE = 'SIGN_UP_FAILURE'; export const CHANGE_NICKNAME_REQUEST = 'CHANGE_NICKNAME_REQUEST'; export const CHANGE_NICKNAME_SUCCESS = 'CHANGE_NICKNAME_SUCCESS'; export const CHANGE_NICKNAME_FAILURE = 'CHANGE_NICKNAME_FAILURE'; export const FOLLOW_REQUEST = 'FOLLOW_REQUEST'; export const FOLLOW_SUCCESS = 'FOLLOW_SUCCESS'; export const FOLLOW_FAILURE = 'FOLLOW_FAILURE'; export const UNFOLLOW_REQUEST = 'UNFOLLOW_REQUEST'; export const UNFOLLOW_SUCCESS = 'UNFOLLOW_SUCCESS'; export const UNFOLLOW_FAILURE = 'UNFOLLOW_FAILURE'; export const ADD_POST_TO_ME = 'ADD_POST_TO_ME'; export const REMOVE_POST_OF_ME = 'REMOVE_POST_OF_ME'; export const signUpAction = (data) => { return { type: SIGN_UP_REQUEST, data, }; }; export const changeNicknameAction = (data) => { return { type: CHANGE_NICKNAME_REQUEST, data, }; }; export const loginRequestAction = (data) => { return { type: LOG_IN_REQUEST, data, } }; export const logoutRequestAction = { type: LOG_OUT_REQUEST, }; const reducer = (state = initialState, action) => produce(state, (draft) => { switch (action.type) { // 로그인 case LOG_IN_REQUEST: draft.state = true; draft.loginError = null; draft.logInDone = false; break; case LOG_IN_SUCCESS: draft.logInLoading = false; draft.logInDone = true; draft.me = dummyUser(action.data); break; case LOG_IN_FAILURE: draft.logInLoading = false; draft.loginError = action.error; break; // 로그아웃 case LOG_OUT_REQUEST : draft.logOutLoading = true; draft.logOutError = null; break; case LOG_OUT_SUCCESS : draft.logOutLoading = false; draft.logOutDone = false; draft.me = null; break; case LOG_OUT_FAILURE : draft.logOutLoading = false; draft.logOutError = action.error; break; // 회원가입 case SIGN_UP_REQUEST : draft.signUpLoading = true; draft.signUpDone = false; draft.signUpError = null; break; case SIGN_UP_SUCCESS : draft.signUpLoading = false; draft.signUpDone = true; break; case SIGN_UP_FAILURE : draft.signUpLoading = false; draft.signUpData = action.error; break; // 닉네임 변경 case CHANGE_NICKNAME_REQUEST : draft.changeNicknameLoading= true; draft.changeNicknameDone= false; draft.changeNicknameError= null; break; case CHANGE_NICKNAME_SUCCESS : draft.changeNicknameLoading = false; draft.changeNicknameDone = true; break; case CHANGE_NICKNAME_FAILURE : draft.changeNicknameLoading = false; draft.changeNicknameData = action.error; break; // 게시글 등록시 사용자 dummy Data에 동기화 case ADD_POST_TO_ME : draft.me.Posts.unshift({ id : action.data}) break; // return { // ...state, // me : { // ...state.me // Posts: [ { id.action.data}, ...state.me.Posts] // } // } // 게시글 삭제 case REMOVE_POST_OF_ME : draft.me.Posts = draft.me.Posts.filter((v) => v.id !== action.data) break; // return { // ...state, // me : { // ...state.me, // Posts : state.me.Posts.filter((v) => v.id !== action.data) // } // } default: break; } }); export default reducer;
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
section 28 과제 중 오류
TypeError: Cannot read properties of undefined (reading 'target') 이런 오류를 어떻게 해결해야 할 지 모르겠습니다!
-
미해결Next.js 시작하기(feat. 지도 서비스 개발)
안녕하세요! 구글 서치 콘솔에 등록하는 도중 다음 오류가 뜹니다
아니요: 'X-Robots-Tag' http 헤더에서 'noindex'가 감지됨페이지 색인을 생성할 수 없음: ‘NOINDEX’ 태그에 의해 제외되었습니다. 라고 뜨는데,Robots.txt 도 제 url 에 맞춰서 변경했는데 뭐가 문제가 되는지 모르겠습니다..!네이버 서치어드바이저에는 잘 등록된 상태 입니다.
-
해결됨Next.js 시작하기(feat. 지도 서비스 개발)
emotion styles 파일이 빌드시 경고로 뜹니다.
저는 scss 대신 emotion 스타일을 사용하고 컴포넌트or 페이지를 스타일 파일과 한폴더에 넣어 사용합니다 (아래와 같은 폴더구조)페이지 폴더가 라우트 기능을 해서인지 다음과 같이 빌드 최적화에 실패햇다고 뜨는 현상이 있는데 컴포넌트폴더 에서는 문제없이 되는데 페이지 폴더에서만 이렇게 되는 원인이 무엇인가요?또 해당 페이지를 컴포넌트로 이동신후 페이지에서 단순 호출만 하게 한다면 최적화가 정상적으로 되는건가요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
컴포넌트 재사용성 질문
이전 강의 섹션 7 "실무용 폴더구조와 props"에서 21분 3초쯤에 src > components에서 한 번만 사용되는 컴포넌트들은 units, 두 번 이상 사용되는 컴포넌트들은 commons폴더에 만들어 준다고 하셨는데 섹션 7 "컴포넌트 재사용성"에서는 만들 컴포넌트는 등록페이지와 수정페이지 두 곳에서 사용되는데 12분 50초쯤에 src > components > commons이 아니라 src > components > units 폴더에 만드시던데 2번 이상 사용될 컴포넌트는 commons안에 만드는 거 아니었나? 혼란스러워서 저도 units 폴더에 따라 만들긴 했지만 제가 제대로 이해못한 것 같습니다... 이 부분에 대해서 한 번 더 설명해 주시면 감사드리겠습니다!
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
아이콘과 글자 사이 간격
안녕하세요! css 싸이월드 1일차 과제 중에 아이콘과 글자 사이의 간격을 조절할 수 있는 방법이 있는 지 궁금해져 질문 드립니다!아래는 제가 작성한 html 코드이고아래는 라이브서버 화면입니다!별과 인스타그램 사이 간격이 위 3개의 글자보다 넓어 신경이 쓰이네요... 차이를 알고자 배경색을 깔아둔 것입니다. 답변 주시면 감사하겠습니다 :)
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
html에 iframe으로 연결했는데 안떠요..
안녕하세요.. 매번 사소한걸로 질문드리고 있어욥...싸이월드 만들기 2탄 수업들으면서 같이 실습하고 있는데 html에는 제대로 입력을 한것같은데 화면에는 제대로 안떠서 문의글 남깁니다... 머가 문제인지 모르겠어요ㅠㅠ
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
variables 값들이 바뀌질 않습니다
const setGraphql = gql` mutation createBoard($writer: String, $title: String, $contents: String) { createBoard(writer: $writer, title: $title, contents: $contents) { _id number message } } `; export default function GraphqlMutationPage() { const [createBoardMutation] = useMutation(setGraphql); const onClickSubmit = async () => { try { const result = await createBoardMutation({ // await 을 빼주면 promise 상태로 변환 variables: { // variables => $ 역할을함 writer: '훈이', title: 'ㅎㅇ', contents: '반갑습니다', }, }); console.log(result); } catch (error) { console.error(error); } }; 다음과 같이 코드를 작성해보았습니다. 데이터 요청은 보내지지만 variables 값들이 바뀌질 않습니다.
-
미해결Next.js 시작하기(feat. 지도 서비스 개발)
naver map 이 출력되지 않습니다.
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 네이버 클라우드 플랫폼에도 사용횟수는 늘어나고 있고 css를 건드려봐도 map이 생성이안되서 height 100% 가 먹히질 않고있습니다.. 뭐가문제일까요 ㅠㅠ++ 개발자 도구 Network 를 열어봐도 잘 받아오고잇고 지도 이미지도 받아오는것을 확인 하였습니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
image upload 주소 질문있습니다
image upload 의 주소가 google로 되어있다고 설명해주셨는데 백엔드 개발자가 google 쪽으로 설정한 것인지 아니면 graphql 에서 기본적으로 google 주소를 가지고 있는 것인지 궁금합니다
-
미해결만들면서 배우는 프론트엔드 DO IT 코딩 (Next.js, Typescript)
클래스 방식말고 (2)
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 먼저 빠르게 답변해주셔서 정말 감사합니다!답변해주신 부분 참고해서 코드를 수정하던 도중 궁금한 점이 생겨 다시 질문 드립니다아래 답변을 참고해서 코드를 변경해봤는데 맞는건지 확인가능할까요?-firebase_admin.tsif (!admin.apps.length) { const config: Config = { credentials: { projectId: process.env.projectId || '', clientEmail: process.env.clientEmail || '', privateKey: process.env.privateKey?.replace(/\\n/g, '\n') || '', }, }; admin.initializeApp({ credential: admin.credential.cert(config.credentials), }); console.info('bootstrap firebase admin'); } else { admin.app(); }else문에 admin.app()을 통해 이미 애플리케이션이 실행되었다면 초기화하지않고 실행한다는 코드인데 이게 맞을까요?? 파이어베이스에 대해 정확히 알지 못해서...ㅠㅠ 번거롭게 해드려 죄송합니다. -if문안에서 로그 안뜨는 문제는 해결했습니다! console.info('bootstrap firebase admin');