[Next.js] 글 목록 가져오기

DU·2024년 7월 8일

Next.js

목록 보기
9/16
post-thumbnail

구축한 백엔드로 글 목록을 동적으로 생성해 볼 것입니다.

그 전에 개념정리부터 할 것입니다.

Next.js뿐만 아니라 React 18버전부터 이렇게 Server Component가 추가되었습니다.

이 두가지는 서로 사용할 수 있는 API가 다릅니다. 또한 , Next.js에서 특별한 조치를 하지 않으면 Server Component로 간주합니다.

언제 Server, client 컴포넌트를 사용할까요?

위의 그림을 보면 S가 server, C가 client component의 사용 사례를 보여줍니다.

서버 컴포넌트는 아래와 같은 경우에 사용합니다.

  • 사용자와 상호작용하지 않는 경우
  • 백엔드에 엑세스하면서 보안적으로 위험한 정보를 주고 받는 경우
  • 정보를 단순히 보여주는 역할을 하는 경우

클라이언트 컴포넌트는 아래와 같은 경우 사용합니다.

  • 서버 컴포넌트로 해결되지 않는 경우
  • 사용자와 상호작용하는 경우
  • useEffect, useState, onClick, onChange와 같은 API를 사용해야 하는 경우
  • useRouter, useParams와 같은 nextjs의 client component API를 사용하는 경우

클라이언트 컴포넌트로 먼저 시도해보고 비효율을 살펴본 후 , 서버 컴포넌트로 전환하는 작업을 해볼 예정입니다.

const [topics, setTopics] = useState([]);
useEffect(() => {
    fetch("http://localhost:9999/topics")
      .then((resp) => resp.json())
      .then((result) => {
        setTopics(result);
      });
  }); 

가져온 데이터를 사용하기 위해 useState를 작성하고 useEffect를 통해 데이터를 서버에서부터 가져옵니다.

이렇게 하면 에러가 발생합니다.

그 이유는 useState는 오직 클라이언트 컴포넌트에서만 동작하기 때문인데 이 모듈을 클라이언트 컴포넌트로 바꾸고 싶다면 제일 위에 “use client”를 추가해야합니다.

하지만 “use client” 를 추가해도 오류가 발생하는 것은 똑같습니다.

use client로 인해 useState는 client컴포넌트가 되었지만,metadata는 서버 컴포넌트로만 사용되기에 client컴포넌트로 사용되었기에 에러가 발생하였습니다.
그래서 meta를 일단 주석처리 해보면 에러가 발생하지 않는 것을 확인할 수 있습니다.

또한 이제 정보를 표시하기 위해 return함수에 코드를 작성해보겠습니다.

<body>
        <h1>
          <Link href="/">WEB</Link>
        </h1>
        <ol>
          {topics.map((topic) => {
            return (
              <li key={topic.id}>
                <Link href={`/read/${topic.id}`}>{topic.title}</Link>
              </li>
            );
          })} 

잘 동작하는지를 볼 수 있습니다.

하지만 아쉬운 점이 있는데 useEffect를 이용해서 data를 fetching하고 있습니다.

문제점

  • 만약에 서버와 클라이언트가 굉장히 멀다면 비효율
  • 자바스크립트를 종료하면 정적인 내용은 보이지만 서버와 통신하는 useEffect를 비롯한 코드들은 실행되지 않기 때문에 컨텐츠는 표시되지 않는다.
  • 보안적인 문제 또한 발생

이 문제를 어떻게 해결할까요?

  1. 다시 서버컴포넌트로 바꿔봅시다. use client 삭제
  2. 오류가 발생하는데 서버컴포넌트에서는 사용할 수 없는 useState, useEffect와 같은 것들을 사용했기 때문입니다.
  3. 서버컴포넌트는 한번 렌더링 되면 클라이언트로 단순히 보내주는 역할만 해주면 되기 때문에 fetch를 사용할 때의 useEffect, useState가 필요가 없어집니다.
  4. await와 promise를 사용하기 위해 function을 async로 바꾸어 줍니다.
const resp = await fetch("http://localhost:9999/topics/");
const topics = await resp.json();
  1. fetch메소드가 호출되고 실행이 끝날 때까지 await를 통해 기다립니다.
  2. 끝나면 json으로 바꾸는 명령이 전달되면 topics데이터를 갖고와 글 목록을 동적으로 생성한 다음에
  3. 그렇게 만들어진 결과를 서버 쪽에 (.next폴더) 저장하고 최종적인 정적인 내용을 js를 빼고 클라이언트로 전송합니다

장점:

  1. 용량이 적어짐, 접근하고 있는 서버가 같은 서버의 주소라면 굉장히 빠르다.
  2. 서버쪽에서 렌더링을 끝내고 데이터를 보내기 때문에 js를 꺼도 코드는 잘 동작합니다.
  3. 그 이유는 서버쪽에서 동적으로 생성한 정적인 내용을 클라이언트로 전달했기 때문입니다.
  4. metadata도 사용 가능합니다.

0개의 댓글