웹 개발/NextJS

NextJS 당근마켓 클론코딩: #5.0 ~ #12.7 필기 내용 정리

restudy 2024. 4. 29. 16:35
반응형

이 포스트에서는 당근마켓 클론코딩의 #5.0 ~ #12.7 단원에서 학습한 내용들을 정리한다.

 

 

# 5.0 Route Handlers

로그인 form을 입력하면 백엔드에서 값을 어떻게 가져가서 확인하고, 로그인을 시켜주는가

<기존 방식>
API route를 만들고, API URL을 이용해서 데이터를 전송

→ 이때 route handler를 만들기 위해서는 파일명을 반드시 route.ts로 해야한다.

→ 그래야 NextJS에서 route handler임을 인식한다.

 

프론트엔드에서 fetch(주소, { method: "POST", body: JSON.stringify({ value: 값 }))로 전송하면, 백엔드에서 request: NextRequest에 대해 await request.json()과 같이 값을 받을 수 있었다.

 

# 5.1 Server Actions

<새로운 방식>
NextJS의 Server Actions를 이용하면 프론트엔드에서 전달한 값을 백엔드에서 받는 과정을 훨씬 간단하게 구현할 수 있다.
함수 내에 "use server";를 작성하면, 이 함수는 서버에서만 실행되도록 해 준다. 

(이때 함수는 비동기 함수이므로 async 함수로 선언해 주어야 한다.)


함수를 선언하고 "use server";를 입력해 준 다음, 이 함수 이름을 form의 props에서 action={함수명}과 같이 작성해 주면 끝이다.
이제 프론트엔드에서 form을 입력하고 제출하면, 해당 함수가 백엔드에서 실행된다. 

(이때 Server Action을 이용해 데이터가 전송된다.)


함수에서 데이터를 받기 위해서는, 매개변수를 'FormData' 타입으로 선언한 다음, 

'변수명.get("form의 name")'과 적어주면 된다.

 

# 5.2 useFormStatus

useFormStatus hook을 사용하면, 컴포넌트가 로딩 중인 상황도 쉽게 컨트롤할 수 있다.
const { pending } = useFormStatus();와 같이 선언한 다음, <button disabled={pending} />과 같이 사용할 수 있다. 

(Component 코드 최상단에 "use client";를 선언해 주어야 한다.)

 

# 5.3 useFormState

const [state, action] = useFormState(함수, 초깃값(null));와 같이 실행한다.
state는 action의 return 값이고, action은 함수를 실행한다.
이때 action은 (action의) 이전 state와 함께 호출된다.


action을 useFormState를 이용해서 넘겨주면, action의 결과를 반환한다.
→ useFormState가 action을 호출하면, action은 formData와 함께 이전에 반환한 state(없으면 초깃값)와 함께 실행된다.

 

# 6.5 Recap

Zod: 데이터에 대한 schema를 정의하여 올바르지 않은 데이터가 백엔드로 전달되는 것을 방지해 준다.
하지만 Zod를 사용하더라도, form 자체에서 validation을 이중으로 처리해 줄 필요는 있다.

formSchema의 safeParse() 메서드: 데이터를 파싱할 때 에러가 발생하더라도 에러를 throw 하지 않고, 데이터와 에러를 반환한다.
result.error.flatten() 메서드: 여러 에러를 하나의 배열에 담아서 반환해 준다. 이를 통해 에러를 더 쉽게 처리할 수 있다.

 

# 6.7 Coerce

Zod에서 z.coerce.number()와 같이 coerce 속성을 이용하면 유저의 입력을 자동으로 number 타입으로 변환해 준다.

 

 

# 7.0 Setup

Prisma: 사용자와 DB 사이의 통역사 역할
DB 내 데이터 구조를 prisma의 언어로 알려주면, prisma가 우리가 연결해 준 DB를 관리해 준다.

 

# 8.3 Iron Session

iron-session: NodeJS에서 session을 처리하기 위한 middleware
getIronSession(): session을 관리할 수 있는 함수로, session 데이터에 접근/조작 가능


session.id = user!.id와 같이 session 값을 설정한 이후에는,

반드시 await session.save()와 같이 session을 저장해 주어야 한다.


로그아웃과 같은 기능을 구현할 때는 const session = await getSession()으로 session을 얻어준 다음,

await session.destroy()와 같이 session을 제거한다.

//@ts-ignore: TypeScript가 다음 줄의 에러를 무시할 수 있게 해 준다.

 

# 8.9 Middleware

/app 폴더가 위치한 경로와 동일한 경로에 middleware.ts를 생성하면, NextJS가 자동으로 이를 middleware로 인식한다. (파일 내 함수 이름 역시 middleware()이어야 한다.)
middleware는 페이지에 접속하기 이전에 페이지 접속 권한 검사 등 다양한 처리들을 수행할 수 있다.

middleware가 특정 페이지에서만 작동하도록 하려면, config라는 객체 내에 작성해주면 된다. (역시 변수명 config로 고정 필수, 정규표현식을 사용할 수도 있고, ! 기호를 붙이면 특정 페이지에서만 middleware가 실행되지 않도록 할 수도 있음)

 

# 8.11 Edge Runtime

NextJS의 middleware는 빠르게 동작할 수 있는 Edge runtime에서 작동하기 때문에 특정 기능은 사용하지 못한다.

(따라서 session이나 cookie 확인, 그리고 redirect 정도만 사용하는 것이 적절)

 

# 9.1 Github Authentication

OAuth: 사용자 인증 방식 (네이버, 카카오 등 다양한 플랫폼 모두 동일한 방식 사용)
github의 경우 다음의 링크에서 새 OAuth를 등록할 수 있다.

https://github.com/settings/applications/new

 

 

# 9.7 Twilio SMS

Twilio를 이용해 SMS 인증 기능을 구현한다.

 

# 10.1 Tab Bar

소괄호 이름 폴더로 라우트 디렉토리들을 묶을 경우 묶인 디렉토리들에는 서로 다른 layout을 적용할 수 있다.

(단순히 라우트에 영향을 받지 않도록 라우트 디렉토리들을 묶는 것만이 장점이 아님)

 

 

# 10.6 Image Hostnames

NextJS의 Image는 이미지를 자동으로 최적화를 해 주어 성능을 향상시키고 빠른 로딩이 되도록 해 준다.
하지만 외부 호스트의 이미지(다른 사이트의 이미지 링크 등)를 불러올 때는 보안 때문에 이 기능이 허용되지 않는다.


따라서 next.config.mjs에서 hostname들을 등록해 주어야 한다.
(nextConfig > images > remotePatterns > hostname)

 

 

# 10.9 Infinite Scrolling

infinite scrolling의 구현: IntersectionObserver를 이용해 페이지의 하단에 도달했는지를 감지할 수 있다.

 

 

# 11.0 Introduction

Zod + React Hook Form + Server Actions를 함께 활용해 Server upload하는 방법을 배운다.
NextJS cacheDB response를 server memory에 저장하여 재사용할 수 있게 해 준다. 이를 통해 DB에 매번 접속 및 로딩하지 않고 데이터를 즉시 볼 수 있다.

 

 

# 11.3 Images Setup

Cloudflare images: 이미지 저장 및 로드, 최적화에 특화된 서비스
user가 server에 요청을 보내면, user → server → cloudflare 순서로 파일이 전송되는 것이 아닌, 

user → cloudflare 순서로 효율적으로 이미지 업로드가 진행된다.
cloudflare는 저장된 image의 URL을 반환하며, 이 URL만 DB에 저장하면 된다.

 

# 11.8 RHF Refactor

react-hook-form을 이용하여 코드를 refactoring 하는 과정
흐름은 유지하면서 코드만 고치는 부분이 많으므로 복습 필요

 

 

# 12.1 Intercepting Routes

폴더명을 "(..)라우트명"과 같이 작성하여 다른 라우트로의 request를 intercept 해 올 수 있다.
이렇게 될 경우 상대 경로로 폴더명을 지정한 폴더의 코드가 먼저 실행되고, 새로고침을 하고 나서는 절대 경로로 해당 위치에 있는 폴더의 코드가 실행된다.
이를 활용하여 modal 창을 구현할 수 있다.

그렇다면 현재 경로에 있는 a라는 라우트를 intercept 하려면?
(.)a 폴더를 하나 더 작성해서 page.tsx를 작성해주면 된다.

(...)은 root directory까지 밖으로 이동하는 것을 뜻한다.


# 12.3 Parallel Routes

두 route의 page가 동시에 렌더링될 수 있도록 해 준다.
slot: parallel route로 지정하려면 route의 폴더명의 맨 앞에 @ 기호를 붙이면 된다. 이를 slot이라고 한다.

구현된 parallel route page는 해당 폴더들을 포함하는 폴더의 layout.tsx에서 인자로 받아서 렌더링해 줄 수 있다.

주의할 점은, route가 redirect 되는 것도 고려해 주어야 한다.
예를 들어 로그인하지 않은 사용자는 "/"로 이동하고 로그인한 사용자는 "/home"으로 이동한다면 이 둘을 모두 고려하여 parallel route page를 둘 다 작성해 주어야 layout.tsx에서 인자를 받을 때 404 에러가 발생하지 않는다.

 

 

# 12.4 Default Routes

위의 내용처럼 parallel route가 match 되는 route가 없을 경우, 404 에러가 발생하게 된다.
이를 피하기 위해서는 위의 내용처럼 각각의 parallel route page들을 만들어주는 방법도 있겠지만, 

default routes를 사용하면 사전에 지정하지 않은 모든 route에 대해 렌더링할 component를 지정해 줄 수 있다.

parallel route 폴더 안에 "default.tsx"라는 이름의 컴포넌트 파일을 생성하면, route가 match 되지 않는 경우 해당 컴포넌트를 렌더링해 준다.

 

+ Code Challenge


Button 컴포넌트 분리하여 use client 사용하지 않아도 되도록 만들 것
modal에 이미지와 product에 대한 정보 DB에서 받아와서 렌더링하기

 

 

 

반응형