[TIL] 241112_Next.js: Server Action - Day16

지코·2024년 11월 12일
0

Today I Learned

목록 보기
52/66
post-thumbnail
export default function Page() {
	return (
		<h1>서버 액션을 통해 리뷰 추가/조회 기능 구현하기 🤓</h1>
    );
}

⚠️ 참고 ⚠️

  1. 먼저 form 태그를 작성할 때 required 키워드를 통해, 사용자의 입력을 강제할 수 있다.

➡️ 클라이언트 측에서의 예외처리

  1. 서버로 넘어간 데이터의 값이 없을 경우 반환하는 코드를 작성한다.
if (!content || !author) {
  return;
}

➡️ 서버 측에서의 예외처리


⚡️ 리뷰 추가 기능 구현하기

먼저 리뷰 생성 API의 형태는 위와 같다. 이를 참고하며 다음과 같이 작성된 코드를 살펴보자.

try {
  // api 경로, fetch 요청의 옵션 객체
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/review`, {
      method: "POST",
      body: JSON.stringify({ bookId, content, author }),
    }
  );

  console.log(response.status);
} catch(err) {
  console.error(err);
  return;
}

위 코드는 리뷰 생성을 위해, 지난 포스트에서 작성한 서버 액션 함수에 추가한 코드이다.

fetch 메서드의 첫 번째 인수로 api 경로를 넣어주는 것은 기존과 같으며, 메서드의 두 번째 매개변수로는 요청의 옵션 객체를 넣어준다. 이 때 API 형태를 참고하여 작성한다.

bookId 값은 서버 액션 함수 내에 존재하지 않으므로, Page 컴포넌트에서 props로 넘겨 받아 넣어준다. content, author 값은 서버 액션을 통해 받은 데이터에서 get 메서드를 통해 꺼내 온 값이다.


⚡️ 리뷰 조회 기능 구현하기

리뷰 조회 API의 형태는 위와 같다. 이를 참고하여 지금까지 해온 방식으로 fetch 메서드를 사용해 리뷰 조회 함수를 구현하면 된다.

async function ReviewList({ bookId }: { bookId: string }) {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/review/book/${bookId}`
  );
  // 예외 처리
  if (!response.ok) {
    throw new Error(`Review fetch failed: ${response.statusText}`);
  } 
  
  const reviews = await response.json();

  return (
    <section></section>
  );
}

먼저 우리 프로젝트는 📁 error.tsx 파일을 통해 예외를 처리하도록 적용해놓았으므로, 에러 발생 시 Error 객체를 던질 수 있도록 처리하였다.

또한 API를 받아와 json화한 reviews 객체의 타입이 any로 추론되고 있는 상태이므로, 이에 대한 타입을 구체화하기 위해 따로 타입을 정의하는 것이 필요하다고 판단하였다.

export interface ReviewData {
  id: number;
  content: string;
  author: string;
  createdAt: string;
  bookId: number;
}

받아 오는 response의 형태를 참고하여 위와 같이 데이터의 타입을 정의하였다.

const reviews: ReviewData [] = await response.json();

따라서 정의한 새로운 타입을 이용하여, 위와 같이 reviews 객체의 타입을 ReviewData의 배열 형태로 선언해줄 수 있다.


import { ReviewData } from '@/types';
import style from './review-item.module.css';

export default function ReviewItem({
  id,
  content,
  author,
  createdAt,
  bookId
}: ReviewData) {
  return (
    <div>
      <div>{author}</div>
      <div>{content}</div>
      <div>
        <div>{new Date(createdAt).toLocaleString()}</div>
        <div>삭제하기</div>
      </div>
    </div>
  );
}

하나의 리뷰를 띄우기 위한 컴포넌트를 ReviewItem이라는 이름으로 구현하였다. 스타일이 적용되지 않은 초기 상태이다.

'삭제하기'는 후에 버튼으로 변경할 예정이다.

return (
  <section>
    {reviews.map((review) => (
      <ReviewItem key={`review-item-${review.id}`} {...review} />
    ))}
  </section>
);

데이터 페칭 후 저장한 reviews 배열을 위에서 선언한 ReviewItem 컴포넌트를 이용해서 화면에 뿌려주면 된다.


Reference

👩🏻‍🏫 한입 크기로 잘라 먹는 Next.js(15+) https://www.inflearn.com/course/한입-크기-nextjs/

profile
꾸준하고 성실하게, FE 개발자 역량을 키워보자 !

0개의 댓글