next.js serverAction & revalidate을 알아보자!

taehyung·2024년 8월 16일

Next.js

목록 보기
3/6

Supabase 와 Prisma!

실제로 서버, 데이터베이스를 사용한 프로젝트에 참여하기전에 간단한 TODO 앱으로 맛보기를 하던 중이었습니다.

지금부터 읽어보실 포스팅은 각 라이브러리와 프레임워크의 상세한 기능이 아닌 프론트엔드와 서버의 통신과정을 가늠할 수 있을 정도의 포스팅입니다.

Supabase

사용용도
실제로 데이터가 저장될 저장공간인 데이터베이스 역할

저는 데이터베이스로 PostgreSql 기반인 Supabase를 사용하였습니다.

supabase는 다양한 기본 API를 제공하고 요즘은 firebase 보다 약간 우위에있는 데이터베이스로 알고있습니다.

프로젝트에 데이터베이스 셋팅을 하고 사용하면 되는데 이번 포스팅은 해당 내용은 아니니 이 부분은 넘어가겠습니다.

Prisma

사용용도
서버에서 데이터베이스와 통신하기위한 sql 문법

데이터베이스를 연결하고 사용하려면 흔히들 말하는 SQL 문법(쿼리문)을 알아야합니다. 데이터베이스와 통신하는 언어거든요. 하지만 기존에 복잡한 쿼리문을 간단한 API를 통해 소통할 수 있게 해주는 녀석이 바로 이 Prisma라는 ORM 인데요.

이 두 녀석을 사용하여 실제로 데이터베이스와 서버를 이용한 TODO앱을 만들어 보았습니다.

⭐️이렇게 생각하면 편해요!
Supabase : 데이터베이스
Prisma : 데이터베이스와 통신하기 위한 문법을 간단한 API로 제공해주는 라이브러리


RouteHandlers

사용용도
restAPI 작성 및 데이터베이스와 통신

라우트 핸들러란, next.js에서 제공하는 기능으로 사용자의 요청에 따라 api를 호출하고 응답을 받을 수 있게 해주는 녀석인데요. 이 녀석을 통해 db와 통신하고 사용자에게 응답을 해줄 수 있습니다.

위에 살펴보았던 Prisma 라는 데이터베이스 통신 라이브러리랑 연관이 있겠죠?

이녀석은 실제로 아래 그림처럼 사용됩니다.

❗️주의
GET, POST, PATCH, PUT, DELETE 등 함수를 선언해서 사용하는데 이 함수명은 예약어입니다. api/todo 경로로 GET 요청을 보내면 알아서 매핑되어서 사용이 되니까 변경하시면 안됩니다!


serverAction

사용용도
API 호출 ( 서버측 데이터페칭 ) 및 데이터 재검증

서버액션이란, Next.js에서 제공하는 기능으로 "use server" 키워드를 사용해 서버측에서 실행되는 비동기함수를 만들어 낼 수 있습니다.

공식문서에서는 위와 같이 설명하고있습니다.

  • 서버컴포넌트와 클라이언트 컴포넌트에서 모두 사용이 가능하다.
  • 단, 선언은 서버컴포넌트에서만 가능하다.

클라이언트 컴포넌트에서는 안됩니다~


에러:
클라이언트 컴포넌트에서 인라인으로 "use server"로 주석 처리된 서버 액션을 정의하는 것은 허용되지 않습니다.

클라이언트 컴포넌트에서 서버 액션을 사용하려면 "use server"를 상단에 추가한 별도의 파일에서 내보내거나, 서버 컴포넌트에서 props를 통해 전달해야 합니다.

서버측에서 실행되는 비동기함수이고 클라이언트 컴포넌트에서 사용이 가능하다는것은 서버에요청하고 응답을 받으라는 용도로 만들어둔것같죠?

주로 데이터를 페칭하는 패턴에서 사용 될 것같습니다.


revalidate

사용용도
데이터 재검증

리벨리데이트란, 데이터 재검증을 통해 유저에게 서버의 신선한 데이터를 제공하는 행위를 말하는데요. 저는 TODO앱을 만들면서 새로운 TODO를 추가했을 때 데이터베이스에 추가된 데이터가 바로 사용자에게 보여지는 부분을 위해 사용했습니다.

프론트엔드의 리액트쿼리 라이브러리와 유사한 기능을 제공합니다.


문제의 서막

우리는 하나의 상태를 여러 컴포넌트에서 공유해야하는 상황에는 그 부모컴트에 상태를 선언합니다.

여기서는 A 컴포넌트죠.

저는 투두리스트를 관리하기위해 위와같은 방식으로

  • B컴포넌트 : 투두리스트 렌더링
  • C컴포넌트 : 투두리스트 추가를 위해 Form 을 통한 상호작용

컴포넌트를 이렇게 분리했습니다.

next.js 에서는 리액트 훅을 사용하는 컴포넌트는 반드시 클라이언트 컴포넌트여야 하는데요.

아마도 서버액션과 실제 데이터베이스 통신을 해보기 전인 프론트앤드 개발자는 저처럼 위와같이 클라이언트 컴포넌트에서 데이터 페칭을하고 상태관리를 통해 UI를 그렸을것이라고 생각이 듭니다.

fetchTodo라는 서버액션은 API를 호출하고 데이터베이스에 저장된 기존의 투두리스트를 페칭하는 함수입니다.

서버측에서 console로 찍어보니 데이터베이스와 통신이 아주 잘 된걸 확인할 수 있었습니다.

진짜 문제 발생

자 이제 가져오는건 됐고 ~ 쓰기를 만들어볼까나 ~?

저는 이렇게 TODO를 입력받고 전송하면,

여기서 API요청을 하면서 기존에 뿌려졌던 TODO리스트를 재검증하여 사용자에게 즉각적인 화면 피드백을 주려고했습니다. 보통 클라이언트 컴포넌트에서 상태관리를하면 사용자에게 즉각적인 리렌더링으로 훌륭한 UX를 제공하잖아요..

아무튼! 이렇게 서버액션을 통해서 API호출을 했습니다. 페이로드도 잘 전달되었습니다.

라우트 핸들러에서 데이터베이스와 통신도 성공해서 쓰기가 아주 잘 됐습니다.

그런데.. 띠용.. 화면이 업데이트 되질 않네요? 새로 작성한 TODO가 화면에 안나타났습니다..

그도 그럴것이 서버에서 데이터를 그리고 가져와서 클라이언트컴포넌트에서 업데이트 하는것이 뭔가 좀 어색해보이긴합니다..

사실 클라이언트 컴포넌트의 이 상태를 업데이트 해주면 간단하게 해결될 일이긴 합니다.

그런데 그럼 데이터베이스와 동기화는 어떻게 해야될까요..? 데이터베이스에 저장할 새로운 투두리스트를 반환받고 상태를 업데이트 하는 방식이 어색한 방법같기도하고 리벨리데이트 기능이 제공되는 next.js 에서는 올바른 방식이 아닌것같아 리벨리데이트 기능을 사용했습니다.

기존의 클라이언트 컴포넌트였던 컨테이너에서 데이터 페칭을 하지 않고 각각의 컴포넌트에서 서버액션을 사용했습니다. 투두리스트의 상태관리또한 하지않습니다.

만들어둔 쓰기용 서버액션에서 데이터베이스에서 조회한 투두리스트를 리벨리데이팅 해서 쓰고난 후 서버에서 다시 데이터를 불러오는 방식으로 진행했습니다.

그런데도 안됩니다... 왜 안될까요.. 개발자도구를 열어서 네트워크탭을 봅니다.. 아무리 추가해도 리벨리데이팅은 되지않습니다..

https://nextjs.org/docs/app/api-reference/functions/revalidateTag

공식문서에는 이렇게하면 된다고 나와있는데...

해결

문제는 서버액션을 사용하는 컴포넌트에 있었습니다. 리벨리데이트는 서버에서만 작동하기 때문에.. 데이터를 그려주는 컴포넌트도 서버컴포넌트여야 했던겁니다.. ㅠㅠ

서버에서 데이터 다시불러오는건데.. 클라이언트 컴포넌트까지 업데이트 될거라 생각했던 내가 바보였던건가..

코드도 더 간결해지고 SEO에도 유리한 앱이 되었습니다. 짜짠~

결론은 서버액션과 라우트 핸들러를 사용해 데이터베이스와 통신하려면 서버컴포넌트일 때 그 이점이 확실하다는겁니다.

요약
1. 클라이언트에서 상호작용
2. 서버액션을 통한 API 요청
3. 라우트 핸들러를 통한 로직 처리 및 데이터베이스 상호작용
4. 서버에서 리벨리데이트를 통한 데이터 캐시 무효화 및 서버컴포넌트 화면 업데이트

profile
Front End

0개의 댓글