import { useEffect, useState } from "react";
import { getFlight } from "../api/FlightDataApi";
import FlightList from "./component/FlightList";
import LoadingIndicator from "./component/LoadingIndicator";
import Search from "./component/Search";
export default function Main() {
// 항공편 검색 조건을 담고 있는 state
const [condition, setCondition] = useState({ departure: "ICN", });
// 항공편 목록을 담고 있는 state
const [flightList, setFlightList] = useState([]);
// 로딩 여부(렌더링 완료 여부)를 담고 있는 state
const [isLoading, setIsLoading] = useState(false);
// 주어진 검색 키워드에 따라 condition 상태를 변경시켜주는 함수
const search = ({ departure, destination }) => {
if (
// 새로 입력한 값(departure, destination 중 하나라도)이 기존 상태 값(condition 객체 내의 값)과 다를 경우 실행
condition.departure !== departure ||
condition.destination !== destination
) {
setCondition({ departure, destination }); // 키: 값이 동일한 경우 축약 가능 (departure: departure, => departure,)
}
};
// Effect Hook을 이용해 AJAX 요청 보내기, 로딩 상태에 따라 로딩 컴포넌트 제공
// condition 조건이 바뀌면, Effect Hook에 의해 getFlight(condition) 함수가 호출
useEffect(() => {
setIsLoading(true); // data를 받아오기 전 로딩 상태를 true로 업데이트
getFlight(condition).then(res => {
setFlightList(res); // res를 받아와 그대로 fligthList 상태 업데이트
setIsLoading(false); // 서버에서 data를 받아온 뒤니 로딩 상태를 false로 업데이트
})
},[condition])
return (
<div>
<Head>
<title>States Airline</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<h1>여행가고 싶을 땐, States Airline</h1>
<Search onSearch={search} /> {/* condition 상태변경 함수 전달 */}
<div className="table">
<div className="row-header">
<div className="col">출발</div>
<div className="col">도착</div>
<div className="col">출발 시각</div>
<div className="col">도착 시각</div>
<div className="col"></div>
</div>
{/* 로딩 중이면 LoadingIndicator, 로딩이 끝나면 FlightList 렌더링 */}
{isLoading ? <LoadingIndicator /> : <FlightList list={flightList} />}
</div>
</main>
</div>
);
}
function Search({onSearch}) { // Main 컴포넌트에서 props로 onSearch 함수 전달받음(구조분해 할당)
// 도착지를 담고 있는 state
const [textDestination, setTextDestination] = useState('');
const handleChange = (e) => { // 입력값 대문자 변환
setTextDestination(e.target.value.toUpperCase());
};
const handleKeyPress = (e) => { // 엔터 키와 버튼 클릭을 감지
if (e.type === 'keypress' && e.code === 'Enter') {
handleSearchClick();
}
};
const handleSearchClick = () => {
// 상위 컴포넌트(Main)에서 props를 받아서 실행
onSearch({departure: 'ICN', destination: textDestination});
};
return (
<fieldset>
<legend>공항 코드를 입력하고, 검색하세요</legend>
<span>출발지</span>
<input id="input-departure" type="text" disabled value="ICN"></input>
<span>도착지</span>
<input
id="input-destination"
type="text"
value={textDestination}
onChange={handleChange}
placeholder="CJU, BKK, PUS 중 하나를 입력하세요"
onKeyPress={handleKeyPress}
/>
<button id="search-btn" onClick={handleSearchClick}>
검색
</button>
</fieldset>
);
}
http://ec2-13-124-90-231.ap-northeast-2.compute.amazonaws.com:81/
GET /flight
parameter | 형식 | 설명 | 필수 포함 여부 |
---|---|---|---|
departure | 출발지 (문자열) | 특정 departure만 조회 | 필수 아님 |
destination | 도착지 (문자열) | 특정 destination만 조회 | 필수 아님 |
// filterBy로 들어오는 값: condition
export function getFlight(filterBy = {}) {
let query = '';
if (filterBy.departure) {
query += `departure=${filterBy.departure}`;
}
if (filterBy.destination) {
query += `&destination=${filterBy.destination}`
}
let url = `http://ec2-13-124-90-231.ap-northeast-2.compute.amazonaws.com:81/flight?${query}`
return fetch(url).then(res => res.json()); // 패치를 통해 쿼리가 포함된 url data를 가져오기(.json() 사용하여 변환)
}
Main 컴포넌트(상위) → Search 컴포넌트(하위)에 search함수를 전달한다.
이 search함수는 주어진 검색 키워드에 따라 condition 상태를 변경한다.
Search 컴포넌트에서 search함수를 구조분해할당으로 받는다. ({onSearch})
검색버튼을 누르거나 엔터를 치면 onSearch함수에 인자를 넣어 실행한다.
삼항 연산자를 사용하여 조건부 렌더링 해준다.
여기서는 isLoading의 상태에 따라 isLoading이 true이면 로딩 인디케이터, false이면 FlightList 컴포 렌더링
{isLoading ? <LoadingIndicator /> : <FlightList list={flightList} />}
useEffect(() => {
setIsLoding(true); // data를 받아오기 전 로딩 상태를 true로 업데이트
getFlight(condition).then(res => {
setFlightList(res); // res를 받아와 그대로 fligthList 상태 업데이트
setIsLoding(false); // 서버에서 data를 받아온 뒤니 로딩 상태를 false로 업데이트
})
},[condition])
condition state가 업데이트 될 때마다 useEffect에 전달된 함수 호출