묻고 답해요
140만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
Cannot return null for non-nullable field ~~~ 에러
위와 같이 작성하여 요청하였을 때이러한 에러가 나타납니다무엇이 문제일까요?
-
해결됨Supabase, Next 풀 스택 시작하기 (feat. 슈파베이스 OAuth, nextjs 14)
3:07에 const result = 입력하는 부분은 복붙인가요??
플러그인이나 단축키가 따로 있는지 기존에 작성하신 코드 복사 붙여넣기인지 궁금합니다.
-
해결됨Next + React Query로 SNS 서비스 만들기
채팅 구현했는데 소켓 연결이 됐다 안됐다 늦게 됐다 합니다.
안녕하세요 선생님강의를 보고 참고해서 채팅 기능을 만들었습니다.그런데 a,b가 채팅화면에 들어왔을때 소켓 연결이 안되거나, 늦게 되거나 하는 경우가 있어서 제가 로직을 잘못짠건지 어딜 확인해야하는건지 조언을 들을수 있을까해서 문의 남깁니다.먼저 서버에서 이렇게 socket.io를 설정해주고/app.jsconst app = express(); const httpServer = new createServer(app); const io = new Server(httpServer, { cors: { origin: 'https://zzimzzim.com', credentials: true, }, });/utils/io.jsmodule.exports = function (io, db) { const userSockets = {}; const nsp = io.of('/messages'); nsp.on('connection', (socket) => { console.log('soket connected'); socket.on('disconnect', () => { console.log('-----------------user disconnected'); }); socket.on('login', (user) => { userSockets[user.id] = socket.id; console.log(userSockets, '-------------------------------userSockets'); console.log(`User ${user.id} connected with socket id ${socket.id} --------- 유저입장`); }) socket.on('sendMessage', async (data) => { try { const roomId = data.room.split('-').sort().join('-'); console.log(roomId, '---------------------------------roomId'); console.log(data, '---------------------------------data'); console.log(userSockets, '---------------------------------userSockets'); let room = await db.Room.findOne({ where: { room: roomId }, include: [ { model: db.User, as: 'RoomSender', attributes: ['id', 'email', 'gender', 'mbti'], include: [{model: db.Image}], }, { model: db.User, as: 'RoomReceiver', attributes: ['id', 'email', 'gender', 'mbti'], include: [{model: db.Image}] }, ] }); if (room) { room = await room.update({ content: data.content }); } else { const roomCreated = await db.Room.create({ SenderId: data.senderId, ReceiverId: data.receiverId, content: data.content, room: roomId, }) console.log(roomCreated, '------------------------------roomCreated') room = await db.Room.findOne({ where: { room: roomId }, include: [ { model: db.User, as: 'RoomSender', attributes: ['id', 'email', 'gender', 'mbti'], include: [{model: db.Image}], }, { model: db.User, as: 'RoomReceiver', attributes: ['id', 'email', 'gender', 'mbti'], include: [{model: db.Image}] }, ] }) } const savedMessage = await db.Message.create({ SenderId: data.senderId, ReceiverId: data.receiverId, content: data.content, room: roomId, }); // console.log(savedMessage, '------------------------Message saved'); console.log(room, '------------------------room saved'); const receiverSocketId = userSockets[data.receiverId]; if (receiverSocketId) { socket.to(receiverSocketId).emit('receiveMessage', savedMessage); socket.to(receiverSocketId).emit('receiveRoom', room); } else { console.log(`User ${data.receiverId} is not connected`); } } catch (error) { console.error('Error saving message:', error); } }); }) }클라이언트에서는선생님이 useSocket만든것과는 다르게useContext를 이용해서/src/app/(afterLogin)/messages/_component/SocketProvider.tsx'use client'; import { useSession } from 'next-auth/react'; import { ReactNode, createContext, useCallback, useEffect, useMemo, useState } from 'react'; import { io, Socket } from 'socket.io-client'; type Props = { children: ReactNode }; type SocketContextType = { socket: Socket | null; isConnected: boolean; disconnect: Function; goDown: boolean; setGoDown: Function; } export const SocketContext = createContext<SocketContextType>({ socket: null, isConnected: false, disconnect: () => { }, goDown: false, setGoDown: () => {}, }) export default function SocketProvider({ children }: Props) { const { data: session } = useSession(); const [socket, setSocket] = useState<any | null>(null); const [isConnected, setIsConnected] = useState(false); const [goDown, setGoDown] = useState(false); const disconnect = useCallback(() => { socket?.disconnect(); setSocket(null); }, [socket]); const value = useMemo(() => { return { socket, isConnected, disconnect, goDown, setGoDown } }, [socket, isConnected, disconnect, goDown]); useEffect(() => { console.log(socket, '-----------------------------------------socket???'); if (!socket) { const socketInstance = io(`${process.env.NEXT_PUBLIC_BASE_URL}/messages`, { withCredentials: true, }); socketInstance.on('connect', async () => { setIsConnected(true); console.log("소켓연결 성공!!!", socketInstance.id); // console.log(socketInstance, '--------------------socketInstance'); }) setSocket(socketInstance); } }, [socket]); useEffect(() => { if (socket?.connected && session?.user?.id) { console.log('--------------------------------------------socket emit login') socket?.emit('login', { id: session?.user?.id }); } }, [session, socket]); return ( <SocketContext.Provider value={value}> {children} </SocketContext.Provider> ) }이런식으로 만들고/src/app/(afterLogin)/messages/layout.tsximport { ReactNode } from 'react'; import SocketProvider from './_component/SocketProvider'; type Props = { children: ReactNode }; export default function Layout({ children }: Props) { return ( <SocketProvider> {children} </SocketProvider> ) }레이에다가 적용해주었습니다.이런식으로 해주면 소켓연결을 한번만 하고 원할때 메세지를 주고 받을 수 있을거라고 생각해서 적용한건데혹시 소켓 연결 관련해서 더 확인해야하거나 수정할 부분이 있을지 궁금합니다.감사합니다!
-
미해결Next + React Query로 SNS 서비스 만들기
주소 변경없이 모달창 구현하기
Q질문 로그인 버튼 클릭시 주소변경없이 모달창을 보이게 하려면 결국 라우팅만 이용해서는 할 수 없고, 기존에 리액트에서 사용하던 모달 state를 관리해주는 방식으로 해야한다. 라고 생각되어집니다. 이 부분에 대해서 강사님의 생각을 여쭤봅니다. 이렇게 생각한 이유는 로그인 버튼 클릭시 주소변경없이 모달창을 띄우려면 우선, 패러렐 라우팅과 인터셉트 라우팅 둘다 사용해야 하며 '/' 주소가 아닌 '/login' 주소로 바뀌어야만 한다. (이때 인터셉트 라우팅을 사용해야 하는 이유는 새로고침이 뒤에있는 모달창을 안보여도, 뒤에있던 화면은 보여야하기 때문이다. )주소가 바뀌어야 하는 이유를 설명하자면 패러렐 라우팅을 '/' 주소로 하게 되면 처음 브라우저에 방문하게 되면 모달창이 보이게 되기 때문이다. 그러므로 로그인 버튼 클릭시 '/login' 의 주소에서 홈화면과 모달창이 보이게 해야한다.
-
해결됨기초부터 배우는 Next YTMusic 클론 코딩 (with next.js 14, UI 마스터)
use client
안녕하세요 ㅎㅎ강의 너무 잘 듣고있습니다.use client 사용하는 이유에 대해서 잘 모르겠어서 질문을 드립니다 .ㅎㅎ설명을 들었을때 server slide rendering 이지만 server side 기능을 하는것이 아니라 client side 로 넘어온다? 로 이해를 했는데 ,그렇다면 굳이 저 위의 지시어 use client 를 사용해야할때가 있을까 ?? 생각을 했습니다 ㅎㅎ
-
해결됨기초부터 배우는 Next YTMusic 클론 코딩 (with next.js 14, UI 마스터)
tailwind.config.ts
tailwind.config.ts 를 변경하려고 하는데 변경이 되지 않습니다.다른 파일들도 수정하려고 보니까 수정이 안되네요ㅠㅠㅠ이렇게해서 생성을 진행했구요.잘은 모르겠지만 npx create-next-app . 로 설치를 진행했는데 권한 에러가 발생하더라구요npm error code EACCES그래서 sudo 를 앞에 붙여서 진행을 했습니다. 혹시 이 문제일까요 ?
-
해결됨Next.js 시작하기
getServerSideProps에서 axios 호출시
const response = await axios.get(`http://localhost:4000/products/${id}`);로 호출할때 클라이언트에서는 별다른 에러 메시지가 나오지 않으나npm run dev로 실행한 서버 터미널에서는 GET /products/backendManager.js.map 500 in 9ms ⨯ AxiosError: Request failed with status code 404 GET /products/react_devtools_backend_compact.js.map 500 in 16ms이라는 에러가 나옵니다.이 파일들을 호출하는 이유가 무엇인가요..?
-
해결됨기초부터 배우는 Next YTMusic 클론 코딩 (with next.js 14, UI 마스터)
6.8 강의 drawer닫기
안녕하세요 . drawer.tsx에 있는 DrawerClose를 사용하면 useState를 통해 상태관리를 안해줘도 되지않나 싶어서 여쭤봅니다.Header쪽에 <DrawerClose><Logo/></DrawerClose>이렇게 감싸주면 drawer가 열렸을때 x버튼을 누르면 똑같이 동작하더라고요.혹시 useState를 사용하신 이유가 있을까요?
-
해결됨Next.js 시작하기
next create-next-app@latest 설치 문제
Aborting installation.Unexpected error. Please report it as a bug: Error: EACCES: permission denied, open '/Users/jeonginn/Library/Preferences/create-next-app-nodejs/config.json.tmp-982595282012e022' at openSync (node:fs:581:18) at attempt (/Users/jeonginn/.npm/_npx/efeac22998af9bf2/node_modules/create-next-app/dist/index.js:8:43165) at Object.writeFileSync (/Users/jeonginn/.npm/_npx/efeac22998af9bf2/node_modules/create-next-app/dist/index.js:8:38664) at Conf._write (/Users/jeonginn/.npm/_npx/efeac22998af9bf2/node_modules/create-next-app/dist/index.js:8:74912) at set store [as store] (/Users/jeonginn/.npm/_npx/efeac22998af9bf2/node_modules/create-next-app/dist/index.js:8:73358) at Conf.set (/Users/jeonginn/.npm/_npx/efeac22998af9bf2/node_modules/create-next-app/dist/index.js:8:71962) at run (/Users/jeonginn/.npm/_npx/efeac22998af9bf2/node_modules/create-next-app/dist/index.js:74:51291) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { errno: -13, code: 'EACCES', syscall: 'open', path: '/Users/jeonginn/Library/Preferences/create-next-app-nodejs/config.json.tmp-982595282012e022'}설치할 때 터미널에서 이런 메세지가 나오네요 ㅠㅠ 권한 문제인거 같아서 구글링 계속 해보면서 해봤는데 안되서 글 남깁니다 ㅠㅠ
-
해결됨Next + React Query로 SNS 서비스 만들기
강의를 다 보고 궁금한점이 생겼습니다! (afterLogin)에 대해서 질문있습니다.
https://github.com/ZeroCho/next-app-router-z/blob/master/lecture/src/app/(afterLogin)/layout.tsx제로초님 강의를 다 듣고 코드를 살펴보던 중 의문이 있어 질문 드립니다.해당 코드를 보면lecture/src/app/(afterLogin)/layout.tsx파일에서거의 최고 부모컴포넌트인 <RQProvider>가 "use client"를 사용하여 클라이언트 컴포넌트가 되는것으로 알고있는데이렇게 한다면 그 하위 컴포넌트들은 전부 클라이언트 컴포넌트가되는게 아닌가요?어떻게 서버컴포넌트를 사용할 수 있는건지 궁금합니다.
-
미해결Next + React Query로 SNS 서비스 만들기
메세지 보내고 백엔드에 저장하는 부분이 어디인지 궁금합니다.
안녕하세요 선생님완강하고 채팅을 구현해보려고 합니다.그런데 강의와 깃헙을 보면soket으로 보내는 내용,쿼리에 데이터 추가하는 내용은 있는데소켓으로 보낸 내용이 백엔드에 저장되는 부분이 보이질 않더라구요,클라이언트에서 소켓으로 데이터를 보내면 그걸 받고 백엔드에서 저장해주는 로직이 따로 있는걸까요?
-
해결됨Supabase, Next 풀 스택 시작하기 (feat. 슈파베이스 OAuth, nextjs 14)
{10.2장] 로그인 후 새로고침 해야 todolist가 보입니다
로그인 후에도 로딩 애니메이션만 계속 돌아요.새로 고침을 눌러야만 todo list 가 보입니다.뭐가 잘못 된걸까요
-
해결됨Supabase, Next 풀 스택 시작하기 (feat. 슈파베이스 OAuth, nextjs 14)
serverComponent 가 갑자기 강의에서나와요
처음부터 쭉 강의를 따라하고 있습니다.9.3 장에서갑자기 serverComponent 라는게 생겼어요.무슨 용도일까요?
-
미해결[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
수업질문
안녕하세요, 수업 중 이해가 되지 않는 부분이 있어 질문 드립니다.훈훈한 JS>섹션7>함수,변수의 호이스팅 강의에서 17:43에서 newLi에 complete 클래스를 추가해주는 기능을 설명에 이해가 되지 않습니다.위에 content는 부분에서는 전체 todoInput.value를 가져와서 덮어씌우는 것으로 이해했는데, 아래 클래스를 추가하는 부분에 정의된 newLi는 엔터로 인해 함수 실행될 때마다 새로운 createElment("li") 값을 가진 변수인데, 여기에 어떻게 이전의 데이터를 가진 특정 배열에만 complete를 넣어줄 수 있는걸까요?
-
해결됨Supabase, Next 풀 스택 시작하기 (feat. 슈파베이스 OAuth, nextjs 14)
supabase.ts 코드 색상이 흰색입니다.
'Generating TypeScript Types' 강의에서 supabase.ts 생성할 때 나오는 코드 색상이 영상에서 나오는 색상하고 달라요.저는 모두 흰색으로 나와서 가독성이 떨어지더라구요.익스텐션이라던지 테마라던지 등등 구글링해서 나오는건 모두 건드려봤는데 바뀌지 않았습니다.이건 어떻게 하면 되나요?
-
미해결Next + React Query로 SNS 서비스 만들기
Next.js 14 배포 후 액세스토큰 업데이트 안되는 문제
안녕하세요 제로초님강의 잘 듣고 있습니다. 사실 이 문제가 몇개월동안 계속 해결이 안되어서 강의를 수강한거나 마찬가지인데요. 아무리 스택오버플로우나, next.js issue에 직접 글을 올려도 해결이 안되어서 이렇게 질문 글 올립니다.일단 Next.js 14 + Express 조합으로 배포를 한 상황이고 jwt 토큰을 쿠키에 담아서 로그인 기능을 구현했습니다.또한 next.js Middleware 내부에서 액세스토큰을 재발급 받아주고 있습니다.순서는 이렇습니다. 로그인 시에 사용자가 아이디 + 비밀번호를 입력해서 서버에게 요청한다.서버에서 해당 아이디 값을 받아서 조회 후, 새로운 리프레시 토큰 + 액세스 토큰을 클라이언트로 보내준다.백엔드 내부 코드는 다음과 같습니다. const newAccessToken = createNewAccessToken(existingUser); const newRefreshToken = createNewRefreshToken(existingUser); const hashedToken = await hashValue(newRefreshToken); await deleteRefreshTokenData(existingUser.id); await createRefreshTokenData(hashedToken, existingUser.id); return res.json({ success: true, accessTokenValue: newAccessToken, refreshTokenValue: newRefreshToken, }); Next.js 측에서 액세스 토큰과 리프레시 토큰을 받아서 API ROUTE로 POST 요청을 날려서 set cookie를 해준다.const sendTokenCookieToHandler = async (accessTokenValue: string, refreshTokenValue: string) => { await fetch('/api/token', { method: 'POST', body: JSON.stringify({ accessTokenValue, refreshTokenValue }), headers: new Headers({ 'Content-Type': 'application/json', }), cache: 'no-store', }); }; export default sendTokenCookieToHandler; ```그 후 액세스 토큰이 만료 되면, Next.js 미들웨어 단에서 리프레시 토큰을 다시 백엔드로 보내서 새로운 액세스 토큰을 받아온다.Next.js 미들웨어 코드는 이렇습니다. export async function middleware(request: NextRequest) { const { accessToken, refreshToken } = getTokenValues(request); if (!accessToken && refreshToken) { const res = await getNewAccessToken(refreshToken); if (res && res.newAccessToken) { const response = NextResponse.next(); const { newAccessToken } = res; response.cookies.set('accessToken', newAccessToken, { expires: new Date(Date.now() + 24 * 60 * 60 * 1000), }); return response; } } return NextResponse.next(); } ``` 받아온 액세스 토큰 값을 아예 middleware 단에서 set cookie 를 통해 쿠키로 설정해준다.근데 여기서 문제는 초기에는 정상적으로 잘 작동합니다.액세스 토큰이 만료 된 후에도 정상적으로 새로운 액세스토큰을 받아오기도 하고요근데 문제는 일정 시간 후에(제가 생각했을때 리프레시토큰이 만료 된 후, 다시 로그인 요청을 보냈을때 같습니다.) 아예 새로운 리프레시 토큰과 액세스 토큰을 제대로 받아오지 못하는거 같습니다.근데 F12 를 켜서 확인해보면 백엔드로 api 콜은 정상적으로 가고 있습니다.. 그래서 현재 다시 재배포를 할때마다 초기 상태로 돌아가서 로그인이 정상적으로 작동 하게 되는데요.어디가 문제인걸까요 ? 여러 오픈톡이나 커뮤니티에 물어봤지만, 어떤분은 Next.js 내부에서 같은 라우트 그룹이면 미들웨어를 거치지 않아서 발생하는 문제라고도 하시는데 초기 배포 당시에, 리프레시 토큰을 처음에 잘 받았을때 일부러 액세스 토큰을 삭제하고 다시 새로고침하면 액세스 토큰을 제대로 잘 받아오고 있습니다.. 도저히 아무리 이리저리 수정해봐도 몇개월 동안 고치지 못해서 이렇게 글 남깁니다. 읽어주셔서 감사합니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
결제관련
결제를 구현하는 중인데여기 프로젝트에서 결제 과정이 로그인 한 후에 그 아이디로 포인트 충천 API를 날려서 포인트를 충전후상세 페이지에서 결제버튼 클릭시 포인트가 충분하면 성공 포인트가 부족하면 실패 이런식으로 만들어져야 하는 건가요??
-
미해결Next + React Query로 SNS 서비스 만들기
서버컴포넌트, 클라이언트 컴포넌트
안녕하세요 . 아직 리액트에 빠져살아서 서버컴포넌트와 클라이언트 컴포넌트 사용 구분이 잘 가지 않아 질문드립니다. 1번 질문.예를들어 3개의 페이지가 존재한다고 했을때, 각 페이지는 navbar(하위컴포넌트)를 가지려고 하는데요 navbar의 버튼은 각 페이지 마다 다 다른 함수로 동작하게 된다고 가정하면, 3개의 페이지 컴포넌트는 'use-client'를 사용하여 클라이언트 컴포넌트가 되어야 하는게 맞나요? 그렇다면 페이지의 하위컴포넌트를 서버컴포넌트로 만들면 서버컴포넌트로 사용하면 ssr을 사용하는 이유가 충분할까요? 2번질문. after_login 폴더 안에 _lib폴더에서 'getTrends'함수로 패치를 했는데요, 결국에는 클라이언트 컴포넌트에서 usequery로 데이터를 패치해오고 있습니다. 그러면 데이터 패치도 클라이언트컴포넌트에서 진행하는것인데, 1번상황에 패치도 2번과 같이 한다면 서버사이드렌더링의 장점은 어떤것이라고 볼 수 있을까요?
-
미해결Next + React Query로 SNS 서비스 만들기
인터셉팅 라우트에서 메타데이터를 적용할수 없는가요?
안녕하세요 선생님유저정보를 모달창으로 보여주게 하기위해아래와같이 user를 사용해서 적용했었습니다.처음 만들었을때 메타데이터도 유저정보에 맞게 변경시켜줘야하는데 인터셉팅 라우터를 사용하면 메타데이터를 적용하지 못한다는 걸 어디서 본거같아서 테스트해보고 적용했었습니다. (user 폴더)그리고나서 테스트를 하던중에 ux가 어색한거같아서 다시 검색해보니 인터셉팅라우트에서 메타데이터 적용하는 부분을 했다는 사람도 있는것 같더라구요 그래서 (.)tester 폴더를 만들어서 실험해봤는데 메타데이터가 적용 안되서혹시 선생님은 인터셉트 라우트에서 메타데이터를 적용하는 방법을 아실까해서 여쭤봅니다! 📦@modal ┣ 📂(.)promise ┃ ┗ 📂form ┃ ┃ ┗ 📜page.tsx ┣ 📂(.)tester ┃ ┣ 📂[userId] ┃ ┃ ┣ 📂_component ┃ ┃ ┃ ┣ 📜UserDetailContent.tsx ┃ ┃ ┃ ┣ 📜UserDetailPromise.tsx ┃ ┃ ┃ ┣ 📜UserDetailTop.tsx ┃ ┃ ┃ ┣ 📜UserInfo.tsx ┃ ┃ ┃ ┗ 📜UsrCarousel.tsx ┃ ┃ ┣ 📂_lib ┃ ┃ ┃ ┣ 📜getSingleUser.ts ┃ ┃ ┃ ┗ 📜getUserPromise.ts ┃ ┃ ┣ 📜layout.tsx ┃ ┃ ┗ 📜page.tsx ┃ ┗ 📜default.tsx ┣ 📂user ┃ ┗ 📂[userId] ┃ ┃ ┣ 📂_component ┃ ┃ ┃ ┣ 📜UserDetailContent.tsx ┃ ┃ ┃ ┣ 📜UserDetailPromise.tsx ┃ ┃ ┃ ┣ 📜UserDetailTop.tsx ┃ ┃ ┃ ┣ 📜UserInfo.tsx ┃ ┃ ┃ ┗ 📜UsrCarousel.tsx ┃ ┃ ┣ 📂_lib ┃ ┃ ┃ ┣ 📜getSingleUser.ts ┃ ┃ ┃ ┗ 📜getUserPromise.ts ┃ ┃ ┗ 📜page.tsx ┗ 📜default.tsx시도했던 방법은 1. page.tsx에서 직접 generateMetadata를 사용.layout.tsx를 만들고 거기에 generateMetadata를 사용후 page.tsx를 children으로 받기여유되실때 확인해주시면 정말 감사하겠습니다!
-
해결됨Next.js 시작하기
bun, biome 사용 질문
안녕하세요, 강의 잘 보고 있습니다.React Native 프로젝트를 진행할 때 Bun을 사용하여 패키지 매니징을 했을 때 굉장히 개발 경험이 쾌적했던 기억이 있습니다.그리고 비교적 최근 ESLint와 Prettier의 단점을 상쇄해줄 Biome라는 솔루션이 나와서 도입해보려고 하던 상태였습니다.선생님은 Bun, Biome에 대해 어떻게 생각하시는지 궁금합니다!