검색 조건을 변경하면, 해당 검색 조건에 맞는 항공권이 필터링되어 목록에 표시되게 만듭니다.
Main.js # 첫화면 컴포넌트, 필터링 상태를 담고 있습니다.
Search.js # 검색 도구 컴포넌트, 필터링 상태를 변경합니다.
FlightDataApi.js # 항공편 정보를 받아오는 API
세군데를 수정해주면 된다
메인 (부모컴포넌트)에 있는 search함수가
search 컴포넌트 (자식컴포넌트)의 검색 버튼 클릭시 실행되어야 한다 - 상태끌어올리기를 사용하자
export default function Main() {
const [condition, setCondition] = useState({
departure: 'ICN'
})
const [flightList, setFlightList] = useState(json)
const [isloading, setloading] = useState(false)
const search = ({ departure, destination }) => {
if (condition.departure !== departure || condition.destination !== destination) {
console.log('condition 상태를 변경시킵니다')
setCondition({departure, destination})
// 1 상태변경 함수인 serach에 condition변경 함수인 setCondition을 이용해 값을 바꿔준다
}
}
useEffect(async() =>{
setloading(true)
setFlightList(await getFlight(condition))
setloading(false)
}, [condition])
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;
}
global.search = search
return (
<div>
<Head>
<title>States Airline</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<h1>
여행가고 싶을 땐, States Airline
</h1>
<Search onSearch={search}/>
// 2 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} />
}
</div>
<div className="debug-area">
<Debug condition={condition} />
</div>
</main>
</div>
)
}
import { useState } from 'react'
function Search({onSearch}) {
// 3 onSearch props를 받아온다
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 = () => {
console.log('검색 버튼을 누르거나, 엔터를 치면 search 함수가 실행됩니다')
// 4 상태 변경 함수 `search`는 Search 컴포넌트의 `검색` 버튼 클릭 시 실행되어야 합니다
// 검색 버튼을 클릭했을때 onChange는 handleChange값이 변경된다고 아래에 적혀있다
// handleChange는 도착지 값이 변경되는 것을 알려주고 있고
// 출발지는 고정하고 도착지의 값을 textDestination으로 변경해주면 된다
// 서치 함수에서 setCondition({departure, destination}) 객체형태로 값을 받아오는걸 알 수 있으니
// 똑같이 값을 넣어줘야 한다
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>
}
export default Search
import flightList from '../resource/flightList'
import fetch from 'node-fetch'
if (typeof window !== "undefined") {
localStorage.setItem('flight', JSON.stringify(flightList));
}
export function getFlight(filterBy = {}) {
// HINT: 가장 마지막 테스트를 통과하기 위해, fetch를 이용합니다. 아래 구현은 완전히 삭제되어도 상관없습니다.
// TODO: 아래 구현을 REST API 호출로 대체하세요.
let json = []
if (typeof window !== "undefined") {
json = localStorage.getItem("flight");
}
const flight = JSON.parse(json) || [];
return new Promise((resolve) => {
const filtered = flight.filter((flight) => {
let condition = true;
if (filterBy.departure) {
condition = condition && flight.departure === filterBy.departure
}
if (filterBy.destination) {
condition = condition && flight.destination === filterBy.destination
}
return condition;
})
setTimeout(() => {
resolve(filtered)
}, 500);
});
}
export default function Main() {
const [condition, setCondition] = useState({
departure: 'ICN'
})
const [flightList, setFlightList] = useState(json)
const [isloading, setloading] = useState(true)
// 로딩상태일때를 구현 , 상태를 만들어준다
const search = ({ departure, destination }) => {
if (condition.departure !== departure || condition.destination !== destination) {
console.log('condition 상태를 변경시킵니다')
// TODO:
setCondition({departure, destination})
}
}
// useEffect로 상태를 변화하는 condition을 FlightDataApi의 getflight로 넘겨준다
useEffect(async() =>{
setloading(true)
setFlightList(await getFlight(condition))
// 필터링 조건인 객체를 인자로 넣어준다
setloading(false)
}, [condition])
// 검색 조건이 바뀔 때 마다 useEffect 실행
// useEffect에서 어떤 값이 바뀔때만 호출하고싶다면 배열 안에
// useEffect로 관리하고 있는 상태인 condition을 넣어준다
useEffect 다른풀이
useEffect(() =>{
setloading(true)
getFlight(condition) // local서버가 아닌 진짜서버에서 데이터를 받아온다
.then(filtered =>{
setFlightList(filtered)
setloading(false)
})
}, [condition])
global.search = search // 실행에는 전혀 지장이 없지만, 테스트를 위해 필요한 코드입니다. 이 코드는 지우지 마세요!
return (
<div>
<Head>
<title>States Airline</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<h1>
여행가고 싶을 땐, States Airline
</h1>
<Search onSearch={search}/>
<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)} /> */}
// getFlight 요청이 다소 느리므로,
// 로딩 상태에 따라 LoadingIndicator 컴포넌트를 표시해야 합니다
// 컴포넌트 내 필터 함수 `filterByCondition` 대신 삼항연산자 사용
{isloading
? <LoadingIndicator />
: <FlightList list ={flightList} />
}
</div>
<div className="debug-area">
<Debug condition={condition} />
</div>
</main>
</div>
)
}
FlightDataApi에서 기존 구현 대신, REST API를 호출하도록 바꿉니다
import flightList from '../resource/flightList'
import fetch from 'node-fetch'
if (typeof window !== "undefined") {
localStorage.setItem('flight', JSON.stringify(flightList));
}
export function getFlight(filterBy = {}) {
// HINT: 가장 마지막 테스트를 통과하기 위해, fetch를 이용합니다. 아래 구현은 완전히 삭제되어도 상관없습니다.
// TODO: 아래 구현을 REST API 호출로 대체하세요.
// fetch 를 사용해 다시 작성한다
let emString = ''
if(filterBy.departure){
emString = emString + `departure=${filterBy.departure}&`
}
if(filterBy.destination){
emString = emString + `destination=${filterBy.destination}`
}
let endpoint = `http://ec2-13-124-90-231.ap-northeast-2.compute.amazonaws.com:81/flight?${emString}`
return fetch(endpoint)
.then(res => res.json())
// let json = []
// if (typeof window !== "undefined") {
// json = localStorage.getItem("flight");
// }
// const flight = JSON.parse(json) || [];
// return new Promise((resolve) => {
// const filtered = flight.filter((flight) => {
// let condition = true;
// if (filterBy.departure) {
// condition = condition && flight.departure === filterBy.departure
// }
// if (filterBy.destination) {
// condition = condition && flight.destination === filterBy.destination
// }
// return condition;
// })
// setTimeout(() => {
// resolve(filtered)
// }, 500);
// });
}