묻고 답해요
156만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결Next + React Query로 SNS 서비스 만들기
/home 의 new QueryClient
/home 페이지에서 prefetch를 해주지 않고 PostRecommends & followingPosts에서 useQuery로만 데이터를 불러와도 상관없나요 ??1번이 맞다고 하면 prefetch를 통해서 dehydrated를 해주는 이유가 궁금합니다.아니면 서버 컴포넌트에서 react-query를 이렇게도 사용할 수 있다를 보여주신건지 궁금합니다:)
-
미해결Next + React Query로 SNS 서비스 만들기
5:42 임포트 단축키
뭔가요?
-
미해결Next + React Query로 SNS 서비스 만들기
NextAuth를 활용한 소셜 로그인 시 authorization code 발급 방법
안녕하세요 강의 수강 후에 자체 프로젝트를 진행하고 있는데 소셜 로그인 처리 중 궁금한 점이 있어 질문 드립니다.기존에는 Google, Naver, Kakao, Facebook 등 5가지 소셜 로그인을 각각 OAuth 리디렉션 방식으로 구현했으나, 이번에는 NextAuth를 활용하여 간편하게 통합적으로 구현하려고 합니다.소셜 로그인은 authorization code 발급용으로만 사용하고 실제 access, refresh token 발급은 자체 서버에서 처리를 하려고 합니다. 따라서 인가 과정만 next auth를 활용하고 callbacks 내부에서 인가 코드를 전달하여 access token 발급 과정을 진행하려 했습니다./api/auth/[...nextauth]/route.ts const authOptions = { // Configure one or more authentication providers providers: [ GoogleProvider({ clientId: process.env.GOOGLE_ID ?? "", clientSecret: process.env.GOOGLE_SECRET ?? "", }), ], callbacks: { async signIn({ account, profile }: any) { if (account.provider === "google") { const response = await fetch( `${process.env.GATEWAY_SERVER_URL}/auth/v1`, { method: "POST", headers: { "Content-Type": "application/json", devicetype: "1", }, body: JSON.stringify({ sns_type: "GOOGLE", key: 인가코드, }), } ); } return true; // Do different verification for other providers that don't have `email_verified` }, }, }; const handler = NextAuth(authOptions); export { handler as GET, handler as POST };하지만 알아본 결과 NextAuth의 callbacks에서는 access token이 발급되고 authorization code는 받을 수 없게 되어있는 것 같은데 authorization code 발급용으로만 사용하기에는 next auth를 사용하는것이 적합하지 않은 것인지 궁금합니다.또한 authorization code를 받을 수 있는 방법이 있다면 알려주시면 감사하겠습니다!
-
미해결Next + React Query로 SNS 서비스 만들기
http://localhost:3000/home 오류 문의드립니다.
영상을 3:29 이 부분을 똑같이 하려고하는데,http://localhost:3000/home로 접속하면 파일이 없다고 합니다..app 안에 (afterLogin) (beforeLogin)로 나뉘고,home 폴더를 만들어서 layout.tsx 와 page.tsx를 만들어홈페이지와 홈 레이아웃을 작성하여루트 레이아웃과 층계별 확인하려고 http://localhost:3000/를 들어가면 루트레이아웃은 잘나오는데http://localhost:3000/home는 페이지가 없다고 나옵니다.. (afterLogin) 안이 아니라 밖으로 app/home/layout.tsx 와 page.tsx가 있어야만 http://localhost:3000/home가 잘나오는데 왜이럴까요?
-
해결됨Next + React Query로 SNS 서비스 만들기
실무에서 리버스 인피니트 스크롤링 최적화 방법
채팅을 계속 올려서 몇개월 치를 사용자가 본다면 위로 채팅 기록이 엄청 쌓일텐데, 실무에서 메모리가 넘치는걸 방지하는 방법으로 사용하시는게 있는지 어떤걸 사용하시는지 궁금합니다.찾아보니 react-window 같은 라이브러리를 사용해서 실제 랜더링 하는 요소 갯수를 제한하고 스크롤을 유지 시켜서 성능 향상을 하는 글을 봤습니다. 실제로 실무에서 이런 방법을 주로 쓰는지 궁금합니다.
-
미해결Next + React Query로 SNS 서비스 만들기
프로필 업로드시 파일명 한글깨짐 현상
회원가입 페이지에서 프로필 이미지를 한글이 포함된 이미지명로 업로드했을때,nextjs의 서버 Formdata에서 한글 파일명이 깨지는 현상이 있습니다. 해결방법이 있을까요??Step1. 회원가입 페이지Step2. 서버 에러 결과회원가입 페이지 경로 : D:\z-com\src\app\(beforeLogin)\_lib\signup.ts업로드시 한글 파일명 출력 확인을 위해 아래코드를 추가해봤습니다. formData.getAll("image").map((data, idx) => { console.log(data); });업로드 이미지명에 한글이 포함되었을때 출력 -- 한글파일명이 깨져서 출력되고 데이터베이스에 저장됩니다.
-
해결됨Next + React Query로 SNS 서비스 만들기
require 문법 질문드립니다.
제가 알기로는 require는 commonjs에서 쓰는걸로 알고 있는데 useEffect내부에서 쓰시는걸 보고 궁금점이 생겨 질문드립니다.require 대신에 dynamic import를 쓰는건 보았는데 require도 클라이언트에서 사용이 가능한가요?
-
미해결Next + React Query로 SNS 서비스 만들기
middleware 질문입니다!
자주 질문드리네요 ㅠ middleware에서 login을 유무를 파악하고 로그인으로 리다이렉트하려고합니다그 이후 로그인이 된다면, 원래 진입하려던 url을 쿼리스트링으로 전달하고 이를 받아 리 다이렉트하는게 목적인데요! 간헐적으로 미들웨어가 실행되지 않는것 같습니다..새로고침을 해야지만 리다이렉트가 가능합니다. 클라이언트에서 세션감지하고 useEffect로 router.replace 해도 동일합니다. 제 생각으로는미들웨어는 admin , contact진입시에는 무조건 실행한다고 알고있었는데 잘못된 거였나요 ㅠ찾아보니 middleware not Working 이슈가 있는 것같긴한데 원인을 도통모르겠습니다 import { auth } from "@/auth"; import { NextRequest, NextResponse } from "next/server"; export const middleware = async (req: NextRequest) => { const session = await auth(); if (!session) { //권한없으면 login 하라 const url = new URL(`http:localhost:3000/auth/login?redirect=${req.url}`); return NextResponse.redirect(url); } //권한있으면 원래대로 return NextResponse.next(); }; export const config = { matcher: ["/admin/:path*", "/contact/:path*"], }; 혹시! useRouter의 redirect는 client에서 이루어지기 때문에 서버 세션갱신이 되지않아서 상이해지는건가요?!에서router.replace(redirectPath);로 변경 window.location.href = redirectPath;
-
해결됨Next + React Query로 SNS 서비스 만들기
NextAuth 질문입니다!
NextAuth에서의 session token을 통해 사용자정보랑 세션쿠키를 전달하고있는데요.만일 access Token이랑 Refresh Token으로 관리를 한다고 한다면, Session Token도 반 강제적으로 사용해야 하는 것같은데 이럴때는 3개의 토큰을 만료일을 컨트롤 해야하는건가요..?예로 access 30분session 1시간refresh 7일 이렇게 가져가서 엑세스와 세션 두가지의 토큰을 다 갱신해주어야 하는건지 아니면 제가 지금 이상한 프로세스를 생각중인지 모르겠네요 .. NextAuth에 리프래시 엑세스토큰을 통상적으로 어떻게쓰는지가 궁금합니다.. session token때문에 너무 혼동이오네요..
-
해결됨Next + React Query로 SNS 서비스 만들기
compose modal 관련 질문입니다. history stack에 강제로 url을 추가 하는 방법이 있나요?
만약 새창에서 /compose/tweet을 열었을 때 X버튼을 누르면 back()으로 동작되어 창이 닫히지 않거나, 이 전페이지 (트위터 창이 아닌 다른 창)으로 이동하는 이슈가 발생하여 x.com은 어떻게 동작되는지 확인했는데, 이미지 처럼 새창에서 /compose/tweet을 열었을 때, history에 home url이 추가가 되어 뒤로가기를 눌렀을 때 홈으로 돌아가는 것 같습니다.이렇게 hitory url을 제어하는 방법이 있을까요? 구글링해도 정보를 얻을 수 없어 글 올립니다ㅠ
-
해결됨Next + React Query로 SNS 서비스 만들기
ReactQuery와 Next를 공부하다가 궁금한 점이 생겼습니다.
React Query가 사실 데이터를 불러오고 캐싱하는 이유가 가장 큰 것으로 알고있습니다.하지만, Next14부터는 fatch에 store 기능이 생기면서 캐싱이 되는걸로 알고 있는데, 그러면 데이터 캐싱만을 사용하며 굳이 React Query를 사용하지 않아도 되는건가요?
-
미해결Next + React Query로 SNS 서비스 만들기
로컬에서는 카카오 로그인이 되는데 vercel 배포했더니 안되네요 혹시 알려주실 수 있을까요..?
/src/middleware.ts import { auth } from './auth'; import { NextResponse, NextRequest } from 'next/server'; export async function middleware(request: NextRequest) { const session = await auth(); if (request.nextUrl.pathname.startsWith('/login')) { if (session) { return NextResponse.redirect(new URL('/', request.url)); } } if (request.nextUrl.pathname.startsWith('/mypage')) { if (!session) { return NextResponse.redirect(new URL('/login', request.url)); } } if (request.nextUrl.pathname.startsWith('/admin')) { if (session?.user?.name !== 'admin') { return NextResponse.redirect(new URL('/', request.url)); } } } export const config = { matcher: ['/mypage/:path*', '/admin/:path*', '/login'], }; /src/auth.ts import NextAuth from 'next-auth'; import KakaoProvider from 'next-auth/providers/kakao'; export const { handlers: { GET, POST }, auth, } = NextAuth({ pages: { signIn: '/login', }, providers: [ KakaoProvider({ clientId: process.env.KAKAO_CLIENT_ID!, clientSecret: process.env.KAKAO_CLIENT_SECRET!, }), ], secret: process.env.NEXTAUTH_SECRET, }); /src/app/api/auth/[...nextauth]/route.ts export { GET, POST } from '@/auth'; 로컬에서는 되는데 vercel 로 배포 하니까 안되네요.. api/auth/error 로 가지고 Failed to load resource: the server responded with a status of 500 () /api/auth/session 이렇게 오류가 나네요 "next-auth": "^5.0.0-beta.19", 입니다
-
해결됨Next + React Query로 SNS 서비스 만들기
Next App Route Framer 도입 문의 !
안녕하세요!클론하다가 React에서 Framer로 레이아웃을 이전 이후로 나누어서 페이지 전환을 스무스하게 animation을 줬던 기억이 있어서 반영해봤는데요.위의 페이지 전환 효과를 next 프로젝트에도 반영해보려고 하는데App Router의 특성? 때문인지 {children} 으로 라우팅을 전달 받기 때문에 이전, 이후가 아닌 공통적인 레이아웃으로 취급되고 명확한 구분(id)가 없기 때문에 부드러운 전환이 잘 안되는 걸까요..유추한 내용이 맞을까요..?타 라이브러리 질문 안받으신다면 죄송함다 ㅠconst Framer = ({ children }: { children: ReactNode }) => { const pathName = usePathname(); return ( <> <AnimatePresence mode="wait" initial={false}> <motion.div key={pathName} initial={{ opacity: 0, x: 20 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -20 }} transition={{ duration: 0.5 }} > {children} </motion.div>{" "} </AnimatePresence> </> ); };
-
미해결Next + React Query로 SNS 서비스 만들기
inline block 을 사용하시는 의미가 궁금합니다 :)
안녕하세요섹션 2 > 레이아웃 클론 강의를 수강 중에 로고에 inline-block 을 사용하신 부분이 있어서요block 으로 해도 비슷한 노출이 되는 듯해서, 어떤 의도가 있으셨을지 또는 다른 효과가 있는지 궁금합니다 :).logo { display: inline-block; height: 56px; margin-top: 2px; }
-
미해결Next + React Query로 SNS 서비스 만들기
msw server 부분에 대한 이해를 한건지 궁금합니다
안녕하세요 강의 잘 듣고있습니다.강의를 듣다가 궁금한 점이, browser.ts와 http.ts 두개를 만든 점 입니다.next는 CSR과 SSR을 둘다 사용하기에, 서버에서도 데이터 처리를 하려고 http.ts를 통해 서버 데이터 처리를 하는 게 맞나요?아래 코드는 브라우저 환경일 때만 brower.ts를 실행시키고 http.ts를 브라우저 환경이든 아니든 항상 켜져있는건가요? if (typeof window !== 'undefined') { if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') { // eslint-disable-next-line global-require require('@/mocks/browser') } } 그렇다면 만약 react에서 사용하게 되면 CSR만 한다는 가정하에 http.ts는 필요 없게 되는건가요?
-
해결됨Next + React Query로 SNS 서비스 만들기
RQProvider 하위의 컨포넌트는 모두 Client component인가요?
"use client";하위의 컴포넌트는 Client로 랜더링 된다고 하신거 같은데,QueryClientProvider가 client에서 랜더링 되는건 아닌가요? 해당 파일을 가보니 'use client'를 사용하고 있어서요.<QueryClientProvider></QueryClientProvider>로 감싸도 그 하위에 컴포넌트들이 SSR가 되는지 궁금합니다. 'use client' import * as React from 'react' import type { QueryClient } from '@tanstack/query-core' export const QueryClientContext = React.createContext<QueryClient | undefined>( undefined, ) export const useQueryClient = (queryClient?: QueryClient) => { const client = React.useContext(QueryClientContext) if (queryClient) { return queryClient } if (!client) { throw new Error('No QueryClient set, use QueryClientProvider to set one') } return client } export type QueryClientProviderProps = { client: QueryClient children?: React.ReactNode } export const QueryClientProvider = ({ client, children, }: QueryClientProviderProps): React.JSX.Element => { React.useEffect(() => { client.mount() return () => { client.unmount() } }, [client]) return ( <QueryClientContext.Provider value={client}> {children} </QueryClientContext.Provider> ) }
-
해결됨Next + React Query로 SNS 서비스 만들기
connect.sid 삭제가 되지 않습니다.
개별적으로 서버를 만들어서 진행중입니다.// 로그인시 서버에서 발급하는 코드 response.cookie('connect.sid', accessToken, { httpOnly: true, sameSite: 'none', secure: false, }); // 프론트에서 아래와 같이 저장 if (res.ok && res.status === 204) { let setCookie = res.headers.get("set-cookie"); if (setCookie) { const parsed = cookie.parse(setCookie); cookies().set("connect.sid", parsed["connect.sid"]); const user = jwtDecode(parsed["connect.sid"]); return { ...user, }; } } // 서버에서 삭제하는 코드 logout(request: any, response: Response) { const { user } = request; response.clearCookie('connect.sid', { httpOnly: true, sameSite: 'none', secure: false, }); ... }로그인 하면 서버에서 쿠키 설정 -> 프론트에서 저장을 진행한 후, 로그아웃시 위 코드처럼 삭제하도록 하고있습니다.강의 하단부에 작성해주신것 처럼 아래와 같이 events부분에 작성하였는데 쿠키 삭제가 되지 않습니다 ㅠㅠ events에 넣지 않고 강의 그대로 했을 때는 s%3..으로 바뀌어서 삭제되지 않습니다. events에 넣었을때는 아예 값도 바뀌지 않고 삭제되지 않습니다. 어떤 작업이 필요할까요 ㅠㅠ //auth.ts events: { signOut: async (data) => { const token = cookies().get("connect.sid"); if (!token) return; const res = await logout(token.value); console.log("signOut"); }, }, // logout fetch export const logout = async (token: string) => { const res = await fetch(`${BASE_URL}/logout`, { method: "POST", headers: { Authorization: `Bearer ${token}`, }, credentials: "include", }); return res; };
-
해결됨Next + React Query로 SNS 서비스 만들기
server ,client 컴포넌트 랜더링 질문입니다!
안녕하세요~직접 만들어보고 비교하려고하는데 의문점이 하나 생겨서요!서버컴포넌트로 Link를 생성하고useSelectedLayoutSegment로 active클래스 처리해주려고 합니다!export default function SideBar() { const links = [ { path: "/home", pathName: "Home" }, { path: "/", pathName: "탐색하기" }, { path: "/", pathName: "쪽지" }, { path: "/", pathName: "프로필" }, ]; return ( <div className={classes.nav}> <div>logo</div> <nav> <ul> {links.map((link, idx) => { return ( <li key={`${link}-${idx}`}> <SideLink href={link.path}>{link.pathName}</SideLink> </li> ); })} </ul> </nav> <button className={classes.btn}>게시하기</button> </div> ); } interface SideLinkProps { children: ReactNode; href: string; } export default function SideLink({ children, href }: SideLinkProps) { const segment = useSelectedLayoutSegment(); const isSegment = href.slice(1); return ( <Link href={href} className={segment === isSegment ? classes.active : undefined} > {children} </Link> ); }근데 랜더링이Sidebar가 서버에서 초기 랜더링 하고client에서 class 반영한다 라고 이해하고 있는데용브라우저에서 "페이지 소스보기"를 했더니이미 class에 active가 반영된 상태로 랜더링 되어있어요캐시도 지우고 빌드해서 npm start 해봐도 "/home" path에서 소스보기 했더니 class가 반영된 상태로 서버에서 랜더링 되어옵니다.hook에 의한 할당될 class는 비워진 상태로 html를 생성하고 이후 client에서 hook을 이용한 클래스 부여가 된다고 알고 있었는데왜 서버에서 세그먼트 훅에 의한 class 처리가 되서 오는건지 궁금합니다!검색해도 명확한 답이 없어서 질문드려요!
-
미해결Next + React Query로 SNS 서비스 만들기
type과 interface를 사용하는 기준이 궁금합니다.
model 폴더에서 PostImage는 interface를 사용하시고 Post컴포넌트에서는 type을 사용하셨는데 두 개를 다르게 사용하는 강사님만의 기준이 있나요 ? 제가 공부한 바로는 간단한 객체 타입일 경우 둘다 사용해도 상관없다. type은 복잡한 유니언 타입을 지정할때 사용한다 interface는 확장이 필요할 경우 사용한다고
-
미해결Next + React Query로 SNS 서비스 만들기
내가 나에게 채팅을 거는 이유
안녕하세요, 강사님, 개발 하는 도중에, test2계정으로 -> test1계정에 메시지를 걸 떄 원래는 test1계정이 나와야하는데, 현재 로그인한 유저의 정보를 불러오는 상황이 생겼습니다.이유가 무엇인지 궁금합니다!!import { HydrationBoundary, QueryClient, dehydrate, } from '@tanstack/react-query'; import style from './profile.module.css'; import UserPosts from './_component/UserPosts'; import { getUserPosts } from './_lib/getUserPosts'; import UserInfo from './_component/UserInfo'; import { auth } from '@/auth'; import { getUserServer } from './_lib/getUserServer'; import { User } from '@/model/User'; export async function generateMetadata({ params }: Props) { const user: User = await getUserServer({ queryKey: ['users', params.username], }); return { title: `${user.nickname} (${user.id})`, description: `${user.nickname} (${user.id})`, openGraph: { title: `${user.nickname} (${user.id}) / Z`, description: `${user.nickname} (${user.id})`, // 프로필 images: [ { url: `https://z.nodebirde.com${user.image}`, // upload width: 800, height: 600, }, ], }, }; } type Props = { params: { username: string }; }; export default async function Profile({ params }: Props) { const { username } = params; const queryClient = new QueryClient(); const session = await auth(); // 사용자 정보 쿼리로 가져옴 await queryClient.prefetchQuery({ queryKey: ['users', username], queryFn: getUserServer, }); // 해당 유저의 게시글 await queryClient.prefetchQuery({ queryKey: ['posts', 'users', username], queryFn: getUserPosts, }); const dehydratedState = dehydrate(queryClient); // 서버쪽에서 쿼리를 해온 것을 나중에 dehydratedState로 받으면 됨. // const user = { // id: 'zerohch0', // nickname: '제로초', // image: '/5Udwvqim.jpg', // }; return ( <main className={style.main}> <HydrationBoundary state={dehydratedState}> <UserInfo username={username} session={session} /> <div> <UserPosts username={username} /> </div> </HydrationBoundary> </main> ); }