훈돌라
2024. 6. 25. TS 개인과제 진척도 본문
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: 텍스트 크기, 굵기, 색상