스파르타 (React_6기) 본캠프

2024. 10. 31. (최종 팀프로젝트(7))

cha123hein 2024. 11. 1. 01:54

1. 문제점 

컴포넌트 분리 후 api를 계속 중복적으로 불러와서 일일 트레픽 1000을 금방 넘겨버림.

 

2. 문제사항

컴포넌트 분리를 하면서 서버 컴포넌트로 동작하도록 작성되었다.

Next.js에서는 클라이언트 컴포넌트('use client'를 선언한 컴포넌트)에서 비동기적인 함수 실행을 곧바로 하지 못하는 문제가 발생할 수 있다. 특히 페이지가 새로 렌더링될 때마다 fetchPlaces 함수가 호출되고, 그로 인해 API 요청이 중복으로 발생하는 문제가 생긴 것이다.

  1. 비동기 함수와 'use client'의 충돌: RecommendedPlaces 컴포넌트가 'use client'로 선언된 상태에서 직접적으로 비동기 로직을 처리하고 있었다. 이는 클라이언트 컴포넌트의 경우 허용되지 않거나 부적절한 방식이다.
  2. 서버와 클라이언트의 호출 타이밍 문제: 서버 측에서 데이터를 미리 가져와서 넘기는 방식과 클라이언트 측에서 데이터를 비동기적으로 가져오는 방식 간의 혼란이 있을 수 있다.

3. 문제 해결 전 코드

'use client';

import React from 'react';
import { fetchPlaces, Place } from '../../components/tourism/fetchApi';
import PlaceCard from '../../components/tourism/placeCard';

interface RecommendedPlacesProps {
  groupedPlaces: Record<string, Place[]>;
}

const RecommendedPlaces = async () => {
  const groupedPlaces = await fetchPlaces();

  return (
    <div className="min-h-screen bg-gray-50 p-4">
      <header className="mb-6 rounded-md bg-blue-500 p-4 text-white">
        <h1 className="font-bold text-xl">추천 국내 여행지</h1>
      </header>

      <main>
        {Object.entries(groupedPlaces).map(([city, places]) => (
          <div key={city} className="mb-8">
            <h2 className="mb-4 text-xl font-semibold">{city}</h2>
            <div className="flex space-x-4 overflow-x-auto pb-4">
              {places.map((place, index) => (
                <PlaceCard
                  key={index}
                  imageUrl={place.firstimage ? place.firstimage : '/placeholder.png'}
                  description={place.supabaseText || '여행지 정보 없음'}
                />
              ))}
            </div>
          </div>
        ))}
      </main>
    </div>
  );
};

export default RecommendedPlaces;

 

4. 문제해결코드

  useEffect(() => {
    const getPlaces = async () => {
      try {
        const places = await fetchPlaces();
        setGroupedPlaces(places);
      } catch (error) {
        console.error('Error fetching places:', error);
      } finally {
        setLoading(false);
      }
    };

    getPlaces();
  }, []);