묻고 답해요
130만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨Next + React Query로 SNS 서비스 만들기
useQuery vs useQueryClient
tanstack query와 next.js 를 함께 사용하면서 의문이 들어 질문합니다!강의의 코드를 보니 같이 prefetch를 해도 유저데이터는 useQueryClient를 사용해서 데이터를 재사용하는듯한데 안에 하위 컴포넌트의 경우 prefetch를하고 useQuery를 사용해서 데이터를 가져오는듯 하더라구요 이 경우도 데이터를 재사용하는건가요? 아니면 새로 가져오는건가요? 그렇다면 똑같이 데이터를 prefetch해도 useQueryClient를 사용해서 가져오는것과 useQuery를 사용해서 가져와야하는 기준이 있을까요? (저의경우 프로젝트 전체를 prefetch후 useQueryClient를해서 데이터를 가져왔더니 데이터를 가져옴과 동시에 fresh가아니라 inactive상태가 되더라구요. ) 좋은강의 감사합니다. 벚꽃같은 제로초 화이팅
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
첫 로그인 후 req.user.id 사용이 어텋게 가능한지 궁금합니다.
..// user.js router.post("/login", isNotLoggedIn, (req, res, next) => { passport.authenticate("local", (err, user, info) => { // ... return req.login(user, async (loginErr) => { if (loginErr) { console.error(loginErr); return next(loginErr); } const fullUserWithoutPassword = await User.findOne({ where: { id: req.user.id }, // ... }); return res.status(200).json(fullUserWithoutPassword); }); })(req, res, next); }); // index.jsconst passport = require("passport"); const local = require("./local"); const { User } = require("../models"); module.exports = () => { passport.serializeUser((user, done) => { done(null, user.id); }); passport.deserializeUser(async (id, done) => { console.log(`deserializeUser`) try { const user = await User.findOne({ where: { id } }); done(null, user); // req.user안에 넣어줌 } catch (error) { console.error(error); done(error); } }); local(); };첫 로그인 할 때는serializeUser만 실행되고,그 이후 요청 부터 deserialzeUser가 실행되어req.user에 db 테이블에 user객체가 저장되는 걸로 이해했습니다.첫 로그인 할 때는 deserializeUser가 실행이 안되어서 req.user가 저장이 안된 상태일텐데 어텋게req.user.id로 fullUserWithoutPassword 에 값을 할당할 수 있는지 궁금합니다.
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
[도메인 연결하기] 로그인 완료 후에 getServerSideProps 실행되지만,회원정보가 null 이 표시 되는 이유를 몰라서 질문드립니다.
React로 Nodebird sns를 시청하고 나서 개인 프로젝트를 만들고 나서 배포하는 과정에서 막히는 부분이 있어서 질문드립니다. 기존에 localhost:3060 에서 로그인 완료후 메인화면으로 이동시 메인화면 서버사이드 렌더링이 실행됩니다.export const getServerSideProps = wrapper.getServerSideProps(async (context) => { const cookie = context.req ? context.req.headers.cookie : ''; axios.defaults.headers.Cookie = ''; if (context.req && cookie) { axios.defaults.headers.Cookie = cookie; } context.store.dispatch({ type: LOAD_MY_INFO_REQUEST, }) context.store.dispatch(END); await context.store.sagaTask.toPromise(); })그래서,const dispatch = useDispatch(); const { me } = useSelector((state) => state.user); me에 데이터가 들어있습니다. [도메인 연결하기] 영상 시청후Route 53, 가비아 주소, 탄력적 ip 주소를 사용하여 백엔드/ 프론트 서버를 실행하였습니다. 회원가입 후 로그인하고 나서 메인 화면으로 이동되면 쿠키가 저장되는 것을 확인했습니다 하지만로그인 후 메인 화면으로 이동하면, 메인page에 서버사이드 렌더링 코드(getServerSideProps)가 실행하고, export const getServerSideProps = wrapper.getServerSideProps( async (context) => { const cookie = context.req ? context.req.headers.cookie : ""; axios.defaults.headers.Cookie = ""; if (context.req && cookie) { axios.defaults.headers.Cookie = cookie; } context.store.dispatch({ type: LOAD_MY_INFO_REQUEST, }); context.store.dispatch(END); await context.store.sagaTask.toPromise(); } ); const dispatch = useDispatch(); const { me } = useSelector((state) => state.user); 이때 로그인한 사용자의 데이터 정보가 null로 표시됩니다.[back logs]왜 me가 null 인지 ? 무엇이 문제인지 모르겠어서 질문드립니다. 진행 순서[로그인 화면]: 아이디와 비밀번호 를 입력하고 확인 버튼을 누른다. 메인화면에서 서버사이드 렌더링 코드부분 실행하여 회원정보를 불러온다. (LOAD_MY_INFO_REQUEST) export const getServerSideProps = wrapper.getServerSideProps(async (context) => { const cookie = context.req ? context.req.headers.cookie : ''; axios.defaults.headers.Cookie = ''; if (context.req && cookie) { axios.defaults.headers.Cookie = cookie; } context.store.dispatch({ type: LOAD_MY_INFO_REQUEST, }) context.store.dispatch(END); await context.store.sagaTask.toPromise(); }) export default Blog;const dispatch = useDispatch(); const { me } = useSelector((state) => state.user); 3. [메인화면] 회원정보를 불러와 회원정보가 null 이여서 로그아웃 버튼으로 변경되지 않습니다. (me 정보가 null 여서 버튼이 변경되지 않습니다.) 쿠기는 유지되어서 로그인 화면으로 가서 로그인 할시 "로그인하지 않은 사용자만 접근 가능합니다" 안내창이 나옵니다.
-
미해결Next + React Query로 SNS 서비스 만들기
[username] 경로와 home 경로로 라우팅할 때 오류
"홈탭 만들면서 Context API" 강좌를 듣고 localhost3000/home에 들어가면 localhost3000/[username] 경로로 들어가지다가(화면에 '프로필 페이지'라고 뜨는 것을 보니 이런 것 같습니다! ) 화면이 빈 화면으로 바뀝니다.. 그리고 왼쪽 섹션에 있는 프로필을 클릭하면 아래와 같은 오류가 뜹니다 ㅠ 무슨 문제일까요? 오류 내용 : ⨯ Error: Cannot find module '/Users/ryuhojun/Documents/z-com/.next/server/app/(afterLogin)/[username]/page.js'Require stack:- /Users/ryuhojun/Documents/z-com/node_modules/next/dist/server/require.js- /Users/ryuhojun/Documents/z-com/node_modules/next/dist/server/load-components.js- /Users/ryuhojun/Documents/z-com/node_modules/next/dist/build/utils.js- /Users/ryuhojun/Documents/z-com/node_modules/next/dist/server/dev/hot-middleware.js- /Users/ryuhojun/Documents/z-com/node_modules/next/dist/server/dev/hot-reloader-webpack.js- /Users/ryuhojun/Documents/z-com/node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.js- /Users/ryuhojun/Documents/z-com/node_modules/next/dist/server/lib/router-server.js- /Users/ryuhojun/Documents/z-com/node_modules/next/dist/server/lib/start-server.js
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
localstorage.setItem 위치 질문
수업에서는 '카운트다운 시작' 버튼 눌러서 Starter 함수가 실행되면 로컬 스토리지가 setInterval 함수로 인해 비워지기 때문에, CounterMaker 함수 내에 if문을 작성하여 해결하고 있습니다.저는 이 방법 말고 사진처럼 starter 함수 내부에서 setInterval 함수(clearTimer라고 작성한..) 호출 위치를 조정하여 해결하였는데, 이 방법에 문제가 있을지 궁금합니다!
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
404 오류 관련 질문
05-05-dynamic-routing-board-mutation05-05-dynamic-routing-board-mutation-moved 계속해서 대조해보지만 게시글 등록하기를 누르고 moved 페이지로 넘어갈 때 404 오류가 뜹니다. catch에서 잡히지 않는걸로 보아 데이터 전송에서 문제가 있는건 아니지 않을까 싶은데, 아무리 봐도 해결책이 보이지 않아 질문 남깁니다.
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
db 시퀄라이즈 관계 설정 및 백엔드 요청 질문입니다!
안녕하세요 제로초님, 강의 잘듣고잇습니다!!! db시퀄라이즈 관계 설정? 질문좀 드리려고요. 강의듣고 블로그를 만들어보려고 백/프론트 구상하고 있는데요, db table설정?을 어떻게 해야할지 헷갈려서요. 메인 페이지는 전체 post를 카테고리(메뉴)별로 나눠서 보여줍니다.메뉴[ study / TIL / portfolio ]를 클릭하면 해당 categories로 저장한 게시글을 보여줍니다 (노란화살표)포스트 작성할 때는 하나의 categories를 선택합니다. 각 게시글은 하나의 카테고리만 가집니다! 헷갈리는 부분은메뉴탭을 눌러서 study / TIL 로 이동했을 때, 전체 post를 가져오는 게 아니라 해당 categories의 post만 가져오고 싶은데, db를 활용해야 하는건지, 백엔드에서 필터링 과정을 해야 하는건지, 헷갈립니다이때 categories를 관계형 테이블?로 만들어서 해당 카테고리로 post를 가져올 수 있나요????백엔드가 전체 db에서 post를 findAll로 가져와, 카테고리로 필터링해서 프론트로 넘겨줘야 하나요?서버에서 전체 post를 받아서 프론트에서 필터링해서 각 컴포넌트에서 사용해야 하나요?? 흠. 뭔가 여러 방법이 떠오르긴 하는데 아직 시도해보지는 않았고 ㅎㅎㅎ 효율적인 방법이 뭔지 알고싶어요!! 제로초님이라면 어떤 방법을 사용하시나요?
-
미해결Next + React Query로 SNS 서비스 만들기
Next와 React-query의 prefetch에 대해
안녕하세요 ! Next14 버전과 tanstack-qeury를 이용해 프로젝트를 진행하던 도중 궁금한 점이 생겨 질문드립니다. Next의 서버 컴포넌트에서 data를 prefetching 하여 사용하려면 다음과 같은 단계를 밟아야 하는 것으로 알고 있습니다. 1. 서버 컴포넌트에서 queryClient.prefetchQuery를 사용해 데이터를 불러오고 이를 dehydrate하여 HydrationBoundary 내에 state로 넘겨준다. 2. 데이터를 사용하는 컴포넌트에서 useQuery로 동일한 데이터를 불러오면 해당 데이터는 prefetch 된 상태로 넘어와 이를 사용한다. 현재 이를 토대로 아래 예시코드와 같이 작성하여 사용중입니다. 이 때 하위 컴포넌트에서 prefetch한 데이터를 사용하려면 useQuery를 써야하기에, 'use client' 를 사용해야하고, 그렇게 되면 그 하위 컴포넌트도 전부 Client Boundary에 들어오게 되는 것으로 알고있는데, 그럼 "Next를 사용하며 얻을 수 있는 장점이 줄어들지 않나 ?" 라는 의문이 생겼습니다. 제가 사용법을 잘못 알고있다거나 Next의 개념에 대해 부족한걸까요 ? 또, HydrationBoundary로 감싸지 않고 queryClient.getQueryData를 이용해 직접 데이터를 가져와 이를 props로 전달해도 기능은 정상적으로 작동하는데, 이 둘의 차이점이 정확히 무엇인가요 ? // 서버 컴포넌트 import { HydrationBoundary, dehydrate, QueryClient, } from "@tanstack/react-query"; import { QUERY_KEY } from "@/constants"; import { requestGetPushAlarmList } from "@/apis/notification"; import NotificationClient from "./Client"; export default async function Page() { const queryClient = new QueryClient(); await queryClient.prefetchQuery({ queryKey: [QUERY_KEY.PUSH_LIST], queryFn: () => requestGetPushAlarmList({}), }); // const { rows: pushList } = queryClient.getQueryData([ // QUERY_KEY.PUSH_LIST, // ]) as unknown as Rows<PushAlarm>; 예시 2. getQueryData로 데이터에 접근 return ( <HydrationBoundary state={dehydrate(queryClient)}> <NotificationClient /> </HydrationBoundary> // <NotificationList pushList={pushList} /> 예시2. props로 직접 데이터 전달 ); } // 하위 컴포넌트 "use client"; import { useQuery } from "@tanstack/react-query"; import { requestGetPushAlarmList } from "@/apis/notification"; import { QUERY_KEY } from "@/constants"; import NotificationList from "./_components/NotificationList"; import ScreenBox from "@/components/ui/ScreenBox"; import Empty from "@/components/ui/Empty"; export default function NotificationClient() { const { data } = useQuery({ queryKey: [QUERY_KEY.PUSH_LIST], queryFn: () => requestGetPushAlarmList({}), select: (data) => data.rows, }); return ( <> {!data?.length ? ( <ScreenBox.CenterBody> <Empty message="알림이 없습니다." /> </ScreenBox.CenterBody> ) : ( <NotificationList pushList={data} /> )} </> ); }
-
미해결Next + React Query로 SNS 서비스 만들기
서버 컴포넌트에서 Server Actions 사용하기
깃허브에 올려놓은 소스(next-app-router-z /ch3-1)을다운받은후에 403 에러발생을 확인하기 위해서아래의 주석을 해제했습니다.src/mocks/handlers.ts http.post('/api/users', async ({ request }) => { console.log('회원가입'); return HttpResponse.text(JSON.stringify('user_exists'), { status: 403, }) }) }), PostMan 에서 http://localhost:9090/api/users?id=js&password=pass&name=js7777호출을 하면 status 값이 의도한 대로 403 Forbidden 이 출력이 됩니다.그런데, 브라우저 개발자모드 Network 에서 보면 Status 값이 200 으로 출력됩니다.서버에서는 분명 403 상태로 보냈고, PostMan에서도 403으로 상태값이 넘어오는데, 왜? 개발자 도구(Network)에서만 상태값이 200으로 출력되는지 모르겠습니다.
-
미해결Next + React Query로 SNS 서비스 만들기
추천탭 게시글작성 오류
추천탭에서 게시글을 작성하면 새로고침 시 사라져버리고 추천탭에서 게시한 게시글이 "팔로우 중" 탭에서 존재하여 좋아요 버튼을 클릭하면 새로고침 시 다시 추천탭에도 해당 게시글이 나타납니다.도무지 뭐가문제인지 모르겠네요ㅠㅠ"use client" import { MouseEventHandler } from 'react'; import style from './post.module.css'; import cx from 'classnames'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Post } from '@/model/Post'; type Props = { white? : boolean; postId: number; } export default function ActionButtons({white, postId}: Props) { const queryClient = useQueryClient(); const commented = true; const reposted = true; const liked = false; const heart = useMutation({ mutationFn: () => { return fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/posts/${postId}/heart`, { method: 'post', credentials: 'include', }) }, // 클릭한 하트 상태를 실시간으로 true로 만들어줌 // post에서 검색결과,추천,팔로잉,답글 등등 쿼리키가 다양한대 어떤 쿼리키인지 무슨상황인지 알 수가 없다. // 그래서 전부 다 해줘야 한다. onMutate() { const queryCache = queryClient.getQueryCache(); const queryKeys = queryCache.getAll().map(cache => cache.queryKey); console.log('queryKeys',queryKeys); queryKeys.forEach((querykey) => { if(querykey[0] === 'posts') { const value:Post | Post[] | undefined = queryClient.getQueryData(querykey); // 게시글 console.log(value) // 싱글포스트 일 수도 있기때문에 조건문 걸어줌. if(Array.isArray(value)){ const index = value.findIndex((v) => postId == v.postId); // 찾고자 하는 게시글이 있는지 확인 if(index > -1) { const shallow = [...value]; shallow[index] = { ...shallow[index], } // 옅은 복사해준것을 쿼리에 전송 queryClient.setQueryData(querykey, shallow); } }else { // 싱글 포스트인 경우 } } }); }, onError() { }, onSettled() { } }) // 댓글 const onClickComment = () => {} // 리트윗 const onClickRepost = () => { } // 좋아요 const onClickHeart:MouseEventHandler<HTMLButtonElement> = (e) => { e.stopPropagation(); if(liked){ // unheart.mutate(); }else{ heart.mutate(); } } return ( <div className={style.actionButtons}> <div className={cx(style.commentButton, { [style.commented]: commented }, white && style.white)}> <button onClick={onClickComment}> <svg width={24} viewBox="0 0 24 24" aria-hidden="true"> <g> <path d="M1.751 10c0-4.42 3.584-8 8.005-8h4.366c4.49 0 8.129 3.64 8.129 8.13 0 2.96-1.607 5.68-4.196 7.11l-8.054 4.46v-3.69h-.067c-4.49.1-8.183-3.51-8.183-8.01zm8.005-6c-3.317 0-6.005 2.69-6.005 6 0 3.37 2.77 6.08 6.138 6.01l.351-.01h1.761v2.3l5.087-2.81c1.951-1.08 3.163-3.13 3.163-5.36 0-3.39-2.744-6.13-6.129-6.13H9.756z"></path> </g> </svg> </button> <div className={style.count}>{1 || ''}</div> </div> <div className={cx(style.repostButton, reposted && style.reposted, white && style.white)}> <button onClick={onClickRepost}> <svg width={24} viewBox="0 0 24 24" aria-hidden="true"> <g> <path d="M4.5 3.88l4.432 4.14-1.364 1.46L5.5 7.55V16c0 1.1.896 2 2 2H13v2H7.5c-2.209 0-4-1.79-4-4V7.55L1.432 9.48.068 8.02 4.5 3.88zM16.5 6H11V4h5.5c2.209 0 4 1.79 4 4v8.45l2.068-1.93 1.364 1.46-4.432 4.14-4.432-4.14 1.364-1.46 2.068 1.93V8c0-1.1-.896-2-2-2z"></path> </g> </svg> </button> <div className={style.count}>{1 || ''}</div> </div> <div className={cx([style.heartButton, liked && style.liked, white && style.white])}> <button onClick={onClickHeart}> <svg width={24} viewBox="0 0 24 24" aria-hidden="true"> <g> <path d="M16.697 5.5c-1.222-.06-2.679.51-3.89 2.16l-.805 1.09-.806-1.09C9.984 6.01 8.526 5.44 7.304 5.5c-1.243.07-2.349.78-2.91 1.91-.552 1.12-.633 2.78.479 4.82 1.074 1.97 3.257 4.27 7.129 6.61 3.87-2.34 6.052-4.64 7.126-6.61 1.111-2.04 1.03-3.7.477-4.82-.561-1.13-1.666-1.84-2.908-1.91zm4.187 7.69c-1.351 2.48-4.001 5.12-8.379 7.67l-.503.3-.504-.3c-4.379-2.55-7.029-5.19-8.382-7.67-1.36-2.5-1.41-4.86-.514-6.67.887-1.79 2.647-2.91 4.601-3.01 1.651-.09 3.368.56 4.798 2.01 1.429-1.45 3.146-2.1 4.796-2.01 1.954.1 3.714 1.22 4.601 3.01.896 1.81.846 4.17-.514 6.67z"></path> </g> </svg> </button> <div className={style.count}>{0 || ''}</div> </div> </div> ) }
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
도메인 연결 후 게시글 작성..
안녕하세요 도메인 연결 후 로그인과 로그아웃이 잘 되고, 새로고침 시에도 유지가 되는데요~게시글이 작성은 안됩니다 ㅠㅠ 회원가입은 되구요!이 다음 강의 S3를 연결하면 게시글이 작성이 되는게 맞을까요? 아니면 현재 오류가 있는건가여..
-
미해결기초부터 배우는 Next YTMusic 클론 코딩 (with next.js 14, UI 마스터)
웹사이트에서 바로 한글로 번역되는거 어떤 프로그램쓰시는건가요?
안녕하세요. 처음 15초쯤에 nextjs소개하면서 나오는 번역프로그램은 어떤걸 쓰시는건가요? 편리해보여서요~
-
해결됨Next + React Query로 SNS 서비스 만들기
next14 app router 배포 nginx index.html 물리기
프로젝트를 하다가 next를 배포해서 nginx에 물리려고 했는데 index html 을 찾아서 물려줘야 된다고 해서 강의에서 나온 nextConfig 에서 output:'export 를 해주면 index html 이 뜨는건 확인을 하였습니다. 근데 문제는 제가 서버에서의 기능을 많이 썼기 때문에 정적으로 배포가 어려움이 있었습니다. 다른 방법이 있을까요..?
-
미해결
Next에서 자동 로그인 구현
안녕하세요 😃 현재 Next.js 사용해 프로젝트 진행중인데 한번 로그인하면 웹에 재접속 시 자동으로 로그인 처리되도록 하고 싶습니다. 현업에서는 어떤 방식으로 진행하는지 궁금합니다! 답변 주시면 정말 정말 감사합니다!!
-
해결됨Next + React Query로 SNS 서비스 만들기
리액트쿼리 prefetch 시에 QueryClient 생성에 대해 질문드립니다.
csr 에서는 useQueryClient로 생성된 QueryClient를 가져와 사용하는 반면에ssr 에서 prefetch 할 때에는 QueryClient 를 새로 생성해서 사용하시더라구요.그럼 ssr에서 생긴 QueryClient csr에서 생긴 QueryClient 두개가 존재하게 되는데, 리액트쿼리가 hydrate 하는 과정에서 알아서 합쳐주는 건지 그 원리가 궁금합니다. 2. prefetch를 할 때마다 QueryClient를 새로 생성해야 하는지 아니면 ssr에서 사용할 QueryClient를 하나 생성해서 공유하는 방식으로 사용해야 하는 것인지, 또 공유해서 사용한다면 예제가 있을까요? 만약 prefetch 할 때마다 QueryClient를 새로 생성해야 한다면 성능상에 문제는 없을까요? prefetch를 난발하는 것을 멈추고 조심히 사용해야 할까요?강의 덕분에 많이 배웠습니다. 좋은 강의 감사합니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
백틱 적용이 안 돼요..
위 화면과 같이 백틱으로 감싸서 사용할 때, 적용이 안 되는데, 서칭을 해보면 Browser 호환 문제라는 말들이 있습니다. 영상에서와 같은 Chrome을 통한 Console창에서 실습 중인데 무엇이 문제일까요?
-
해결됨Next + React Query로 SNS 서비스 만들기
강좌 보면서 개인프로젝트에 적용중입니다. build시 "Arrow" cannot be used as a JSX component 에러가 납니다.
./src/_components/Carousel.tsx 110:6 Warning: React Hook useEffect has a missing dependency: 'nextFn'. Either include it or remove the dependency array. react-hooks/exhaustive-deps (....lint warning문구 생략) info - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules Linting and checking validity of types .Failed to compile. ./src/_components/Carousel.tsx:137:12 Type error: 'Arrow' cannot be used as a JSX component. Its type 'FC<PropsWithChildren<ArrowProps>>' is not a valid JSX element type. Type 'FunctionComponent<PropsWithChildren<ArrowProps>>' is not assignable to type '(props: any, deprecatedLegacyContext?: any) => ReactNode'. Type 'ReactElement<any, any> | null' is not assignable to type 'ReactNode'. Type 'ReactElement<any, any>' is not assignable to type 'ReactNode'. Property 'children' is missing in type 'ReactElement<any, any>' but required in type 'ReactPortal'. 135 | className={`h-full w-full ${inArrow ? 'absolute' : ''} max-w-full`}> 136 | {!!showNavButton && ( > 137 | <Arrow | ^ 138 | direction="left" 139 | executeFn={prevFn} 140 | inArrow={inArrow} error Command failed with exit code 1. 'use client'; import { FC, PropsWithChildren, useEffect, useState } from 'react'; interface ArrowProps { direction: 'left' | 'right'; executeFn: () => void; inArrow?: boolean; hoverStyle?: string; } const Arrow: FC<PropsWithChildren<ArrowProps>> = ({ direction, executeFn, inArrow, hoverStyle, children, ...props }) => { const [hoverColor, setHoverColor] = useState(hoverStyle || undefined); useEffect(() => { hoverStyle && setHoverColor(`hover:${hoverStyle}`); }, [hoverStyle]); const returnString = direction === 'left' ? '<' : '>'; return ( <div onClick={executeFn} className={`${inArrow ? 'absolute z-50' : ''} ${direction === 'left' ? 'left-0 top-0 rounded-l-lg' : 'right-0 top-0 rounded-r-lg'} center-vertical flex h-full w-[30px] cursor-pointer text-[30px] ${hoverColor && hoverColor}`} {...props}> {returnString} {children} </div> ); }; export default Arrow; next build를 했을때 해당 에러가 Arrow컴포넌트에서 발생하였습니다. Arrow컴포넌트에서 제가 정의한 FC<PropsWithChildren<ArrowProps>>타입이 유효한 JSX element type이 아니라는 메시지 인거 같습니다. 이 에러가 나는 이유가유효한 JSX엘리먼트가 아니어서 일것같아서return 하는 jsx문법에 오류가 있는지 확인하려div 겉에도 fragment로 감싼다거나returnString을 해주는 중괄호 부분도 fragment로 감싸거나children도 감싸보았습니다.그러나 똑같은 에러가 발생하고 있는 상황입니다. const returnString = direction === 'left' ? '<' : '>'; 혹시 위의 코드가 문제가 발생할까 싶어서 SVG파일을 만들어조건에따라 왼쪽 오른쪽 SVG 파일 컴포넌트를 return 문 안에서 렌더링 해주었는데여기서도 동일한 에러가 발생하였습니다. Type error: 'LeftSvg' cannot be used as a JSX component. Its type '({ className, width, height, onClick, cyAttribute, }: { className?: string | undefined; width?: number | undefined; height?: number | undefined; onClick?: (() => void) | undefined; cyAttribute?: string | undefined; }) => JSX.Element' is not a valid JSX element type. Type '({ className, width, height, onClick, cyAttribute, }: { className?: string | undefined; width?: number | undefined; height?: number | undefined; onClick?: (() => void) | undefined; cyAttribute?: string | undefined; }) => JSX.Element' is not assignable to type '(props: any, deprecatedLegacyContext?: any) => ReactNode'. Type 'Element' is not assignable to type 'ReactNode'. Property 'children' is missing in type 'Element' but required in type 'ReactPortal'. 24 | }, [hoverStyle]); 25 | > 26 | const returnString = direction === 'left' ? <LeftSvg /> : <RightSvg />; | ^ 27 | 28 | return ( 29 | <div error Command failed with exit code 1. 참고로'DatePicker' cannot be used as a JSX component. Its instance type 'ReactDatePicker<undefined, undefined>' is not a valid JSX element.이런 에러가 타입에러 발견 된 적이 있어서 package.json파일에 "resolutions": { "@types/react": "^18.0.0" }, resolutions로 버전을 위와 같이 맞춰주어서해결한 적이 있습니다.
-
미해결Next + React Query로 SNS 서비스 만들기
리액트 v5 useQuery onSuccess 관련 질문드립니다!
리액트 쿼리v5 부터 useQuery onSuccess 가 사라진걸로 알고있는데요! useQuery로 데이터패칭이 끝나면 zustand나 전역상태관리에 받아온 데이터를 저장하고싶은데 어떤식으로 하면될까요??
-
해결됨Next + React Query로 SNS 서비스 만들기
회원가입시 redirect가 안됩니다.
클라이언트 컴포넌트에서 Server Actions 사용하기에서 가입하기를 누르면response에는 message: null이 잘 오는데 redirect에서 에러가 납니다.404 SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON at JSON.parse (<anonymous>) at parseJSONFromBytes (node:internal/deps/undici/undici:5329:19) at successSteps (node:internal/deps/undici/undici:5300:27) at fullyReadBody (node:internal/deps/undici/undici:1447:9) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async specConsumeBody (node:internal/deps/undici/undici:5309:7) at async onSubmit (webpack-internal:///(action-browser)/./src/app/(beforeLogin)/_lib/signup.ts:49:21) at async C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:39:406 at async t2 (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:38:6412) at async rS (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:41:1369) at async doRender (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\base-server.js:1378:30) at async cacheEntry.responseCache.get.routeKind (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\base-server.js:1539:28) at async DevServer.renderToResponseWithComponentsImpl (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\base-server.js:1447:28) at async DevServer.renderPageComponent (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\base-server.js:1844:24) at async DevServer.renderToResponseImpl (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\base-server.js:1882:32) at async DevServer.pipeImpl (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\base-server.js:895:25) at async NextNodeServer.handleCatchallRenderRequest (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\next-server.js:269:17) at async DevServer.handleRequestImpl (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\base-server.js:791:17) at async C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\dev\next-dev-server.js:331:20 at async Span.traceAsyncFn (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\trace\trace.js:151:20) at async DevServer.handleRequest (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\dev\next-dev-server.js:328:24) at async invokeRender (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\lib\router-server.js:174:21) at async handleRequest (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\lib\router-server.js:353:24) at async requestHandlerImpl (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\lib\router-server.js:377:13) at async Server.requestListener (C:\Users\user\Desktop\projects\z-com\node_modules\next\dist\server\lib\start-server.js:140:13)at async onSubmit (webpack-internal:///(action-browser)/./src/app/(beforeLogin)/_lib/signup.ts:49:21) 에러가 난것을 확인했을때 다른것은 되는데 redirect가 안되는 것 같습니다.signup.ts는"use server"; import { redirect } from "next/navigation"; import { signIn } from "@/auth"; export default async function onSubmit(prevState: any, formData: FormData) { if (!formData.get("id") || !(formData.get("id") as string)?.trim()) { return { message: "no_id" }; } if (!formData.get("name") || !(formData.get("name") as string)?.trim()) { return { message: "no_name" }; } if ( !formData.get("password") || !(formData.get("password") as string)?.trim() ) { return { message: "no_password" }; } if (!formData.get("image")) { return { message: "no_image" }; } let shouldRedirect = false; try { const response = await fetch( `${process.env.NEXT_PUBLIC_BASE_URL}/api/users`, { method: "post", body: formData, credentials: "include", } ); console.log(response.status); if (response.status === 403) { return { message: "user_exists" }; } console.log(await response.json()); shouldRedirect = true; await signIn("credentials", { username: formData.get("id"), password: formData.get("password"), redirect: false, }); } catch (err) { console.error(err); return { message: null }; } if (shouldRedirect) { redirect("/home"); } return { message: null }; } ESLint 오류가 나서 return {message:null}을 추가해준것과export default async function onSubmit(prevState: any, formData: FormData) {}async function onSubmit 형태로 바꾼것 외에는 건드린게 없고,공지사항대로 @auth/core와 next-auth 버전을npm i @auth/core@0.27 next-auth@5.0.0-beta.11 msw@2.1이렇게 설정해줬고,.env.local도NEXT_PUBLIC_API_MOCKING=enabled API_MOCKING=hello NEXT_PUBLIC_BASE_URL=http://localhost:9090/ .env도AUTH_SECRET=mustkeepinsecret NEXT_PUBLIC_API_MOCKING=enabledSingupModal.tsx"use client"; import style from "./signup.module.css"; import onSubmit from "../_lib/signup"; import BackButton from "@/app/(beforeLogin)/_component/BackButton"; import { useFormState, useFormStatus } from "react-dom"; function showMessage(messasge: string | null) { if (messasge === "no_id") { return "아이디를 입력하세요."; } if (messasge === "no_name") { return "닉네임을 입력하세요."; } if (messasge === "no_password") { return "비밀번호를 입력하세요."; } if (messasge === "no_image") { return "이미지를 업로드하세요."; } if (messasge === "user_exists") { return "이미 사용 중인 아이디입니다."; } return ""; } export default function SignupModal() { const [state, formAction] = useFormState(onSubmit, { message: null }); const { pending } = useFormStatus(); return ( <> <div className={style.modalBackground}> <div className={style.modal}> <div className={style.modalHeader}> <BackButton /> <div>계정을 생성하세요.</div> </div> <form action={formAction}> <div className={style.modalBody}> <div className={style.inputDiv}> <label className={style.inputLabel} htmlFor="id"> 아이디 </label> <input id="id" name="id" className={style.input} type="text" placeholder="" required /> </div> <div className={style.inputDiv}> <label className={style.inputLabel} htmlFor="name"> 닉네임 </label> <input id="name" name="name" className={style.input} type="text" placeholder="" required /> </div> <div className={style.inputDiv}> <label className={style.inputLabel} htmlFor="password"> 비밀번호 </label> <input id="password" name="password" className={style.input} type="password" placeholder="" required /> </div> <div className={style.inputDiv}> <label className={style.inputLabel} htmlFor="image"> 프로필 </label> <input id="image" name="image" required className={style.input} type="file" accept="image/*" /> </div> </div> <div className={style.modalFooter}> <button type="submit" className={style.actionButton} disabled={pending} > 가입하기 </button> <div className={style.error}> {showMessage(state?.message || null)} </div> </div> </form> </div> </div> </> ); } showMessage에 TS오류나서 타입을 state?.message || null로 바꿔준것 외에는 없습니다.캐시도 다 삭제하고 mock서버랑 next서버 다 껐다가 다시 키고 vscode도 껐다가 다시 켜도 똑같습니다.. 리다이렉트가 안됩니다 ㅠㅠ 자꾸 404 SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON이 나옵니다... auth.ts도 바꾼것이 없습니다..import NextAuth from "next-auth" import CredentialsProvider from "next-auth/providers/credentials"; import {NextResponse} from "next/server"; export const { handlers: { GET, POST }, auth, signIn, } = NextAuth({ pages: { signIn: '/i/flow/login', newUser: '/i/flow/signup', }, providers: [ CredentialsProvider({ async authorize(credentials) { const authResponse = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}}/api/login`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ id: credentials.username, password: credentials.password, }), }) if (!authResponse.ok) { return null } const user = await authResponse.json() console.log('user', user); return { email: user.id, name: user.nickname, image: user.image, ...user, } }, }), ] });
-
해결됨기초부터 배우는 Next YTMusic 클론 코딩 (with next.js 14, UI 마스터)
themeprovider
만들어놓은 themeprovider파일 어떻게 자동으로 import 추가하나요? 저는 컴포넌트 눌러도 뜨는게 없어서요ㅠ