AJAX
요청Side Effect
는 useEffect에서 다루기FlightDataApi
의 getFlight
를 검색 조건과 함께 요청getFlight
의 결과를 받아, flightList
상태를 업데이트filterByCondition
를 사용하지 않습니다.flightList JSON
을 사용하지 않습니다 (초기값은 빈 배열로 둡니다)getFlight
요청이 다소 느리므로, 로딩 상태에 따라 LoadingIndicator
컴포넌트를 표시1 번 ~ 5 번 함께 풀이
✅ 해설
⚡ Main.js 부분
import Head from 'next/head';
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';
import Debug from './component/Debug';
// 후반 테스트를 진행할 때 아래 import를 삭제합니다.
// import json from '../resource/flightList';
// ↑ 지워주면 해결.
export default function Main() {
// 항공편 검색 조건을 담고 있는 상태
const [condition, setCondition] = useState({
departure: 'ICN',
});
const [flightList, setFlightList] = useState([]);
// 기존에 json 대신에 불러올 배열을 위해서 빈 배열의 형태로 [] 변경.
const [isLoading, setIsLoading] = useState(false);
// 주어진 검색 키워드에 따라 condition 상태를 변경시켜주는 함수
const search = ({ departure, destination }) => {
if (
condition.departure !== departure ||
condition.destination !== destination
) {
console.log('condition 상태를 변경시킵니다');
// 문제
// search 함수가 전달 받아온 '항공편 검색 조건' 인자를 condition 상태에 적절하게 담아보세요.
setCondition({ departure, destination })
// 풀이
// const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값); 를 기억하자!
// 따라서 setCondition : condition을 변경하는 함수.
// 위에 state인 [condition, setCondition] 부분에 'state 갱신 함수'인 setCondition을 이용해서,
// search 함수가 전달 받아온 '항공편 검색 조건' 인자를 넣어 줌.
}
};
// ↓ 여기서부터
// const filterByCondition = (flight) => {
// let pass = true;
// if (condition.departure) {
// pass = pass && flight.departure === condition.departure;
// }
// if (condition.destination) {
// pass = pass && flight.destination === condition.destination;
// }
// return pass;
// };
// ↑ 여기까지 지워주기.
// Effeck Hook을 이용해 AJAX 요청
// 더불어, 네트워크 요청이 진행됨을 보여주는 로딩 컴포넌트(<LoadingIndicator/>)를 제공
useEffect(async () => {
// 로딩 여부를 참으로 만들고
setIsLoading(true)
await getFlight(condition).then((data) => {
setFlightList(data);
// 로딩 여부를 거짓(로딩완료)으로 만들기
setIsLoading(false);
});
}, [condition])// condition 상태가 변할 때마다 실행시켜줌.
//풀이 1.
// useEffect(함수, [종속성1, 종속성2, ...]) 사용.
// 첫 번째 매개변수는 콜백 함수로서 부수 효과를 정의
// 이 콜백 함수는 컴포넌트가 마운트되거나 업데이트될 때 실행
// async와 await을 넣어줌으로서 로딩화면도 함께 구현.
// 풀이 2.
// getFlight (condition).then((data) => setFlightList(data)); 비동기 Promise 사용.
// getFlight 함수에 인자로 condition이 오고,
// 반환된 데이터를 setFlightList 함수에 인자로 전달 해서, flightList 상태로 설정.
// 항공편 컴포넌트의 상태로 업데이트하고 화면에 반영이 된다.
// 풀이 3.
// 배열 내의 종속성의 값이 변할 때, 첫 번째 인자의 함수가 실행.
// 이 배열에 포함된 값들이 변경될 때마다 useEffect 콜백 함수가 실행.
// condition 값이 변경될 때마다 getFlight 함수를 호출하여 새로운 항공편 데이터를 가져올 수 있다.
global.search = search;
// 실행에는 전혀 지장이 없지만, 테스트를 위해 필요한 코드입니다. 이 코드는 지우지 마세요!
return (
<div>
<Head>
<title>States Airline</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<h1>여행가고 싶을 땐, States Airline</h1>
{/* 문제 */}
{/* 검색 화면이 Search 컴포넌트로 분리되어야 합니다 */}
<Search onSearch={search} />
{/* 풀이 */}
{/* Search 컴포넌트로 search인 상태 변경 함수를 내려주어야하기 때문에 */}
{/* onSearch props로 전달해준다 */}
<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>
{/* <FlightList list={flightList.filter(filterByCondition)} /> */}
{isLoading ? <LoadingIndicator /> : <FlightList list={flightList} />}
{/* 풀이 */}
{/* 조건식으로 삼항연산자 이용. */}
{/* 'isLoading' 로딩중이라면? */}
{/* <LoadingIndicator /> 를 보여주고, */}
{/* 로딩중이 아니라면 (끝났다면,) <FlightList />를 보여준다. */}
{/* <FlightList list={flightList} /> 형태인 이유는 */}
{/* FlightList 컴포넌트에 list prop으로 flightList 배열을 전달하기 위해서 */}
</div>
<div className="debug-area">
<Debug condition={condition} />
</div>
<img id="logo" alt="logo" src="codestates-logo.png" />
</main>
</div>
);
}
FlightDataApi
에서 기존 구현 대신, REST API를 호출하도록 바꾸기StatesAirline
서버에서 항공편 정보를 요청(fetch
)✅ 해설
⚡ FlightDataApi.js 부분
import flightList from '../resource/flightList';
import fetch from 'node-fetch';
if (typeof window !== 'undefined') {
localStorage.setItem('flight', JSON.stringify(flightList));
}
export function getFlight(filterBy = {}) {
const querystring = new URLSearchParams(filterBy)
return new Promise((resolve, reject) => {
setTimeout(() => {
fetch(
`http://ec2-43-201-32-255.ap-northeast-2.compute.amazonaws.com/flight?${querystring}`,
{
headers: {
'Content-Type': 'application/json',
},
}
).then(res => res.json())
.then(data => resolve(data))
.catch(error => reject(error));
}, 500);
});
}
// setTimeout 안에 넣어야 0.5초 시간동안 로딩중인 화면 표현이 가능하기때문에 구현 목적으로 넣어줌.