학습 Next.js - Day 08 / SSR 실습

이유승·2024년 10월 8일

Next.js 학습

목록 보기
9/27



1. SSR 실습

데이터 페칭 함수 구현

import { BookData } from "@/types";

export default async function fetchBooks(): Promise<BookData[]> {
  let url = `http://localhost:12345/book`;

  try {
    const response = await fetch(url);
    return await response.json();
  } catch (err) {
    console.error(err);
    return [];
  }
}
export interface BookData {
  id: number;
  title: string;
  subTitle: string;
  author: string;
  publisher: string;
  description: string;
  coverImgUrl: string;
}
  • fetchBooks는 fetch 메소드를 이용해서 서버에서 모든 도서 데이터를 가져오는 역할을 수행한다.

  • 따라서 우선 해당 함수의 반환값의 타입은, 비동기 호출의 반환값을 의미하는 Promise를 적용하고. 반환되는 도서 데이터들의 타입 파일인 BookData를 제네릭으로 적용해준다. 반환값은 배열 형식이므로 'BookData[]'이 된다.



페이지 컴포넌트에서 getServerSideProps 함수로 페칭 함수 호출 및 데이터 반환 준비

export const getServerSideProps = async () => {
  const allBooks = await fetchBooks();

  return {
    props: {
      allBooks,
    },
  };
};
  • 페이지 컴포넌트의 실행 전에 데이터를 페칭해오고 싶다면? getServerSideProps 함수 내부에 동작해야하는 코드들을 작성하면 된다.

  • 그리고 받아온 데이터는 return 키워드를 통해 반환해주면 된다.

getServerSideProps 함수에서 데이터 페칭 작업이 2개 이상 이루어질 경우

	const allBooks = await fetchBooks();
    const recoBooks = await fetchRandomBooks();
  • 이렇게 데이터 페칭 함수를 순차적으로 호출되도 되지만.. 이런 직렬 방식은 작업이 많을 수록 수행 속도가 느려지는 문제가 있다.
  const [allBooks, recoBooks] = await Promise.all([
    fetchBooks(),
    fetchRandomBooks(),
  ]);
  • 따라서 이렇게 Promise.all 메소드를 이용해서 데이터 페칭을 병렬 방식으로 변경하여 동시에 수행되도록 하는 것이 좋다.

  • Promise.all, 인수로 전달한 배열 내부의 모든 비동기 함수들을 동시에 실행시키는 메소드.



페이지 컴포넌트에서 데이터를 받아서 적절하게 처리

export default function Home({
  allBooks,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
  return (
    <div className={style.container}>
      <section>
        <h3>등록된 모든 도서</h3>
        {allBooks.map((book) => (
          <BookItem key={book.id} {...book} />
        ))}
      </section>
    </div>
  );
}
  • 받아온 데이터는 페이지 컴포넌트에서 필요 사항에 맞게 사용하면 된다. (강의 프로젝트에서는 가져온 데이터를 map 함수를 통해 화면에 순차 렌더링하고 있다.)



검색 기능 구현

쿼리 스트링을 이용해서 데이터 페칭 함수로 검색 키워드를 전달하기

  • 검색 창에 사용자가 키워드를 입력하면, 이것이 서버로 넘어가서 데이터 검색에 사용되어야 한다. 우선 입력 값을 서버에 넘겨주어야 한다. 가장 흔한 방법은 쿼리 스트링을 통하는 것.
export const getServerSideProps = async (
  context: GetServerSidePropsContext
) => {
  const q = context.query.q;
  const books = await fetchBooks(q as string);

  return {
    props: {
      books,
    },
  };
};
  • 일단 입력값을 페이지 컴포넌트에서 처리하는 기능부터 구현해보자. getServerSideProps 함수에서는 이런 상황에 맞춰 context라는 인자를 제공해주고 있다. 인자에 대응하는 GetServerSidePropsContext 타입도 제공해준다.

  • context는 현재 브라우저에서 받은 요청에 해당하는 모든 정보가 포함되어 있다. 쿼리 스크링 또한, context 객체 내부에 query라는 이름으로 포함된다.

  • getServerSideProps에서 context와 query를 이용해서 쿼리 스트링을 꺼내온 다음, 데이터 페칭 함수로 넘겨주면 된다.

데이터 페칭 함수에서 키워드를 받아 서버로 요청을 보내기

export default async function fetchBooks(
  q?: string
): Promise<BookData[]> {
  let url = `http://localhost:12345/book`;
  
  if (q) {
    url += `/search?q=${q}`;
  }
  
  ...
  
}  
  • 학습 프로젝트에서는 일전에 구현한 fetchBooks의 내용을 수정해주면 된다. 따로 함수를 구현해도 되지만, 하나의 함수에서 여러 상황을 대응하게 하는 것도 좋은 방법.

  • 우선 검색값이 존재하지 않을 수도 있다. 따라서 ?를 붙여 선택적 프로퍼티로 설정해준다.

  • if문을 사용하여, 검색 키워드가 존재할 때만 서버로 요청을 보낼 때 url의 구성이 달라지도록 한다.

context 사용시 주의할 점.

export const getServerSideProps = async (
  context: GetServerSidePropsContext
) => {
  const id = context.params!.id;
  const book = await fetchOneBook(Number(id));

  return {
    props: {
      book,
    },
  };
};
  • id 값을 이용해서 특정 데이터만을 호출하는 상황에서도 context를 이용한다.

  • URL 파라미터를 이용할 경우, context 내부에 params 객체의 값을 가져오면 되는데. params은 context에 존재하지 않을 수도 있기 때문에, 단언 연산자!를 사용하여 params의 값이 반드시 존재한다고 선언해주어야 한다.

  • 다만 학습 프로젝트의 해당 페이지의 경우, id의 값이 존재하지 않는 상황이 100% 없기 때문에 !을 사용하는 것이다. 다른 프로젝트를 수행할 때에는 params의 상황이 어떤지 반드시 파악해두어야 한다.









00. 강의 소개.

profile
프론트엔드 개발자를 준비하고 있습니다.

0개의 댓글