Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags
more
Archives
Today
Total
관리 메뉴

훈돌라

2024. 6. 25. TS 개인과제 진척도 본문

카테고리 없음

2024. 6. 25. TS 개인과제 진척도

훈돌라 2024. 6. 25. 20:45

 

CountriesApi.ts

api 호출

import axios from "axios";

export const CountriesApi = async () => {
  try {
    const response = await axios.get("https://restcountries.com/v3.1/all");
    return response.data;
  } catch (error) {
    console.error("컨트리 못 불러옴", error);
    throw error;
  }
};

 

try 블록 내에서 axios.get 메서드를 사용하여  https://restcountries.com/v3.1/all 로 GET 요청을 보낸다.

이 요청이 성공하면, 응답 데이터 (response.data)를 반환한다.

요청이 실패하면, catch 블록이 실행된다.

 

 


App.tsx

Country Interface

interface Country {
  name: {
    common: string;
  };
  region: string;
  flags: {
    png: string;
  };
  isdone: boolean;
  area: number;
}

Country 인터페이스는 Country 데이터의 구조를 정의하고, 국가 이름, 지역, 국기 이미지, favorite 여부 (isdone), 면적(area) 정보 (id 값 대신 사용) 를 포함한다.


상태관리

const [countries, setCountries] = useState<Country[]>([]);
const [loading, setLoading] = useState<boolean>(true);

 

countries = 국가 목록 저장 

loading = 데이터 로딩 여부 저장


useEffect 훅

useEffect(() => {
  const getCountries = async () => {
    try {
      const data = await CountriesApi();
      console.log(data);
      setCountries(data);
    } catch (error) {
      console.error(error);
    } finally {
      setLoading(false);
    }
  };

  getCountries();
}, []);

 

 

컴포넌트가 마운트 될 때 CountriesApi 로부터 국가 데이터를 가져온다.

데이터를 성공적으로 가져오면 countries 상태에 저장하고, 로딩 상태를 false로 설정한다.


toogleCountry 함수

const toogleCountry = (area: number) => {
  setCountries(
    countries.map((country) =>
      country.area === area ? { ...country, isdone: !country.isdone } : country
    )
  );
};

 

이 함수는 주어진 면적(area)을 가진 국가의 isdone 상태를 토글합니다. 즐겨찾기에 추가하거나 제거할 때 사용됩니다.


로딩 상태 처리

if (loading) {
  return <div>Loading...</div>;
}

데이터가 로딩 중이면 "Loading..." 메시지를 표시합니다.


좋아하는 나라와 일반 나라 분리

const favoriteCountry = countries.filter((country) => country.isdone);
const oneCountry = countries.filter((country) => !country.isdone);

 

favoriteCountry는 isdone이 true인 국가들로 구성된 배열입니다.

oneCountry는 isdone이 false인 국가들로 구성된 배열입니다.


렌더링

return (
  <>
    {/* 좋아하는 나라 */}
    <CountryList
      title="좋아하는 나라"
      countries={favoriteCountry}
      toogleCountry={toogleCountry}
    />
    ;{/* 기본 나라 */}
    <CountryList
      title="나라"
      countries={oneCountry}
      toogleCountry={toogleCountry}
    />
    ;
  </>
);

 

 

CountryList 컴포넌트를 두 번 사용하여 즐겨찾기 국가와 일반 국가를 각각 표시한다.

title prop을 통해 각 목록의 제목을 설정한다.

countries prop을 통해 국가 배열을 전달한다.

toogleCountry prop을 통해 국가의 즐겨찾기 상태를 토글하는 함수를 전달한다.

 


CountryList.tsx

Props interface

interface Props {
  title: string;
  countries: Country[];
  toogleCountry: (area: number) => void;
}

Props 인터페이스는 CountryList 컴포넌트가 받아야 하는 속성을 정의한다.

 

toogleCountry: 국가의 면적을 인자로 받아서 호출되는 함수. 주어진 면적의 국가의 isdone 속성을 토글한다.
(id 값 대신 국가의 면적을 id 값 용도로 사용함)


렌더링

 

const CountryList = ({ title, countries, toogleCountry }: Props) => {
  return (
    <>
      <div>
        <h1 className="text-4xl font-bold text-center m-4">{title}</h1>
        <ul className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 m-4">
          {countries.map((country) => (
            <CountriesCard
              key={country.name.common}
              country={country}
              toogleCountry={toogleCountry}
            />
          ))}
        </ul>
      </div>
    </>
  );
};

export default CountryList;

CountryList 컴포넌트는 Props 인터페이스에서 정의한 속성들을 내려받아서 사용한다.

  • title: 제목을 h1 요소로 표시. Tailwind CSS 클래스를 사용하여 스타일을 지정한다.
  • countries: 국가 배열을 map 메서드를 사용하여 순회하며 CountriesCard 컴포넌트로 각각의 국가를 전달한다.
  • toogleCountry: 각 CountriesCard 컴포넌트에 이 함수를 전달하여 클릭 시 호출되도록 한다.

Tailwind CSS 클래스를 사용하여 스타일을 지정합니다.

  • text-4xl, font-bold, text-center, m-4: 제목의 텍스트 크기, 굵기, 중앙 정렬, 마진을 설정한다.
  • grid, grid-cols-1, gap-4, sm:grid-cols-2, md:grid-cols-3, lg:grid-cols-4, m-4: ul 요소에 그리드 레이아웃을 설정하여 반응형 디자인을 구현한다.

CountryCard.tsx

const CountryCard: React.FC<Props> = ({ country, toogleCountry }) => {
  const { name, region, flags, isdone } = country;

  const handleClick = () => {
    toogleCountry(country.area);
  };

  return (
    <>
      {isdone && (
        <li
          className="bg-white rounded-lg shadow-md p-4 flex items-center space-x-4 hover:bg-gray-700 cursor-pointer"
          onClick={handleClick}
        >
          <img
            src={flags.png}
            alt={`${name.common} flag`}
            className="w-16 h-16 object-cover rounded-full"
          />
          <div>
            <h2 className="text-xl font-bold">{name.common}</h2>
            <p className="text-gray-500">Region: {region}</p>
          </div>
        </li>
      )}

      {!isdone && (
        <li
          className="bg-white rounded-lg shadow-md p-4 flex items-center space-x-4 hover:bg-gray-700 cursor-pointer"
          onClick={handleClick}
        >
          <img
            src={flags.png}
            alt={`${name.common} flag`}
            className="w-16 h-16 object-cover rounded-full"
          />
          <div>
            <h2 className="text-xl font-bold">{name.common}</h2>
            <p className="text-gray-500">Region: {region}</p>
          </div>
        </li>
      )}
    </>
  );
};

Tailwind CSS 클래스를 사용하여 스타일을 지정한다.

  • bg-white, rounded-lg, shadow-md, p-4, flex, items-center, space-x-4, hover:bg-gray-700, cursor-pointer: 배경색, 테두리 반경, 그림자, 패딩, flex 박스 정렬, 아이템 간 간격, hover 시 배경색, 커서 모양 등
  • w-16, h-16, object-cover, rounded-full: 이미지의 너비, 높이, 객체 맞춤, 둥근 모양
  • text-xl, font-bold, text-gray-500: 텍스트 크기, 굵기, 색상