๐ก Part 1: ํญ๊ณต๊ถ ๋ชฉ๋ก ํํฐ๋ง
๐งฉ Main ์ปดํฌ๋ํธ์์ ํญ๊ณตํธ์ ์กฐํํฉ๋๋ค
โ Main ์ปดํฌ๋ํธ ๋ด search
ํจ์๋ ๊ฒ์ ์กฐ๊ฑด์ ๋ด๊ณ ์๋ ์ํ ๊ฐ์ฒด condition
์ ์
๋ฐ์ดํธํด์ผ ํฉ๋๋ค
> const [condition, setCondition] = useState({
departure: 'ICN', });
const search = ({ departure, destination }) => {
if (
condition.departure !== departure ||
condition.destination !== destination
) {
console.log('condition ์ํ๋ฅผ ๋ณ๊ฒฝ์ํต๋๋ค');
setCondition({ departure, destination }) /* search๊ฐ ์คํ๋ ๋ setCondition์ผ๋ก condition์ departure, destination์ํ๋ฅผ ์
๋ฐ์ดํธ */
}
};
๐งฉ Search ์ปดํฌ๋ํธ๋ฅผ ํตํด ์ํ ๋์ด์ฌ๋ฆฌ๊ธฐ๋ฅผ ํ์ตํฉ๋๋ค
โ ๊ฒ์ ํ๋ฉด์ด Search ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌ๋์ด์ผ ํฉ๋๋ค
โ Search ์ปดํฌ๋ํธ์๋ ์ํ ๋ณ๊ฒฝ ํจ์ search
๊ฐ onSearch
props๋ก ์ ๋ฌ๋์ด์ผ ํฉ๋๋ค
> <main>
<h1>์ฌํ๊ฐ๊ณ ์ถ์ ๋, States Airline</h1>
<Search onSearch={search} /> /* Search ์ปดํฌ๋ํธ๋ก ํ๋ฉด์ ํ์ํจ๊ณผ ๋์์ 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>
</div>
โ ์ํ ๋ณ๊ฒฝ ํจ์ search
๋ Search ์ปดํฌ๋ํธ์ ๊ฒ์
๋ฒํผ ํด๋ฆญ ์ ์คํ๋์ด์ผ ํฉ๋๋ค
function Search({onSearch}) {
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 ํจ์๊ฐ ์คํ๋ฉ๋๋ค');
onSearch({departure: 'ICN', destination: textDestination}) / ๊ฒ์ ๋ฒํผ์ ๋๋ฅด๊ฑฐ๋, ์ํฐ๋ฅผ ์น๋ฉด(handleKeyPress) Prop์์ Onsearch๋ช
์ผ๋ก ๋ฐ์ searchํจ์ ์คํ /
};
๐ก Part 2: AJAX ์์ฒญ
๐งฉ Side Effect๋ useEffect์์ ๋ค๋ค์ผ ํฉ๋๋ค
โ ๊ฒ์ ์กฐ๊ฑด์ด ๋ฐ๋ ๋๋ง๋ค, FlightDataApi์ getFlight๋ฅผ ๊ฒ์ ์กฐ๊ฑด๊ณผ ํจ๊ป ์์ฒญํด์ผ ํฉ๋๋ค
โ getFlight์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์, flightList ์ํ๋ฅผ ์
๋ฐ์ดํธํด์ผ ํฉ๋๋ค
โ ๋์ด์, ์ปดํฌ๋ํธ ๋ด ํํฐ ํจ์ filterByCondition
๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค
โ ๋์ด์, ํ๋์ฝ๋ฉ๋ flightList JSON์ ์ฌ์ฉํ์ง ์์ต๋๋ค (์ด๊ธฐ๊ฐ์ ๋น ๋ฐฐ์ด๋ก ๋ก๋๋ค)
โ getFlight ์์ฒญ์ด ๋ค์ ๋๋ฆฌ๋ฏ๋ก, ๋ก๋ฉ ์ํ์ ๋ฐ๋ผ LoadingIndicator ์ปดํฌ๋ํธ๋ฅผ ํ์ํด์ผ ํฉ๋๋ค
const [isLoading, setIsLoading] = useState(false); /* ๋ก๋ฉ์ํ๋ฅผ ์ํ ๋ณ์, ์ํ๊ฐ true์ผ๊ฒฝ์ฐ ๋ก๋ฉํ๋ฉด ๋ํ๋จ
useEffect(() =>{
setIsLoading(true) / getFlight ์คํ์ ๋ก๋ฉ ํ๋ฉด ๋ํ๋จ /
getFlight(condition) / getFlightํจ์์ condition๋ณ์ ๋ฃ์ด์ ์คํ /
.then((filterlist) =>{
setFlightList(filterlist) / ์คํ์ ์ฑ๊ณตํ ๊ฒฝ์ฐ setFlightList์ ์ ๋ฌ /
setIsLoading(false) / ๋ก๋ฉ ํ๋ฉด ์ฌ๋ผ์ง๊ฒํจ /
})
}, [condition]) / condition ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์คํ /
๐งฉ FlightDataApi์์ ๊ธฐ์กด ๊ตฌํ ๋์ , REST API๋ฅผ ํธ์ถํ๋๋ก ๋ฐ๊ฟ๋๋ค
โ ๊ฒ์ ์กฐ๊ฑด๊ณผ ํจ๊ป StatesAirline ์๋ฒ์์ ํญ๊ณตํธ ์ ๋ณด๋ฅผ ์์ฒญ(fetch)ํฉ๋๋ค
getFlight(filterBy = {}) {
let nothing = '' / ๋ณ์ nothing ์ ์ธ /
if(filterBy.departure){
nothing += departure={filterBy.departure}& /* ๋ณ์ nothing์ departure๊ฐ ํ ๋น */ } if(filterBy.destination){ nothing += destination={filterBy.destination} / ๋ณ์ nothing์ destination๊ฐ ํ ๋น /
}
let url = http://ec2-13-124-90-231.ap-northeast-2.compute.amazonaws.com:81/flight?${nothing} / ๋ฐ์์ฌ url์ ๋ณ์ nothing๋ฃ์ด์ ์ด๋ค ๊ฐ์ ๊ฐ์ ธ์ฌ์ง ํ ๋น /
return fetch(url).then((res) => res.json()) / jsonํ์ผ๋ก ๋ฐ์์ด /
}
Main ์ปดํฌ๋ํธ
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๋ฅผ ์ญ์ ํฉ๋๋ค.
export default function Main() {
// ํญ๊ณตํธ ๊ฒ์ ์กฐ๊ฑด์ ๋ด๊ณ ์๋ ์ํ
const [condition, setCondition] = useState({
departure: 'ICN',
});
const [flightList, setFlightList] = useState([]);
// ์ฃผ์ด์ง ๊ฒ์ ํค์๋์ ๋ฐ๋ผ condition ์ํ๋ฅผ ๋ณ๊ฒฝ์์ผ์ฃผ๋ ํจ์
const search = ({ departure, destination }) => {
if (
condition.departure !== departure ||
condition.destination !== destination
) {
console.log('condition ์ํ๋ฅผ ๋ณ๊ฒฝ์ํต๋๋ค');
// TODO: search ํจ์๊ฐ ์ ๋ฌ ๋ฐ์์จ 'ํญ๊ณตํธ ๊ฒ์ ์กฐ๊ฑด' ์ธ์๋ฅผ condition ์ํ์ ์ ์ ํ๊ฒ ๋ด์๋ณด์ธ์.
setCondition({ departure, destination })
}
};
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; // ์คํ์๋ ์ ํ ์ง์ฅ์ด ์์ง๋ง, ํ
์คํธ๋ฅผ ์ํด ํ์ํ ์ฝ๋์
๋๋ค. ์ด ์ฝ๋๋ ์ง์ฐ์ง ๋ง์ธ์!
// TODO: Effeck Hook์ ์ด์ฉํด AJAX ์์ฒญ์ ๋ณด๋ด๋ณด์ธ์.
// TODO: ๋๋ถ์ด, ๋คํธ์ํฌ ์์ฒญ์ด ์งํ๋จ์ ๋ณด์ฌ์ฃผ๋ ๋ก๋ฉ ์ปดํฌ๋ํธ(<LoadingIndicator/>)๋ฅผ ์ ๊ณตํด๋ณด์ธ์.
// useEffect(() => {
// }, [])
const [isLoading, setIsLoading] = useState(false);
useEffect(() =>{
setIsLoading(true)
getFlight(condition)
.then((filterlist) =>{
setFlightList(filterlist)
setIsLoading(false)
})
}, [condition])
// TODO: ํ
์คํธ ์ผ์ด์ค์ ์ง์์ ๋ฐ๋ผ 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>
</div>
{isLoading ? <LoadingIndicator /> : <FlightList list={flightList} />}
<div className="debug-area">
<Debug condition={condition} />
</div>
<img id="logo" alt="logo" src="codestates-logo.png" />
</main>
</div>
);
}
Search ์ปดํฌ๋ํธ
import { useState } from 'react';
function Search({onSearch}) {
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 ํจ์๊ฐ ์คํ๋ฉ๋๋ค');
onSearch({departure: 'ICN', destination: textDestination})
// TODO: ์ง์์ ๋ฐ๋ผ ์์ ์ปดํฌ๋ํธ์์ props๋ฅผ ๋ฐ์์ ์คํ์์ผ ๋ณด์ธ์.
};
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;
FlightDataApi ์ปดํฌ๋ํธ
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 nothing = ''
if(filterBy.departure){
nothing += departure=${filterBy.departure}&
}
if(filterBy.destination){
nothing += destination=${filterBy.destination}
}
let url = http://ec2-13-124-90-231.ap-northeast-2.compute.amazonaws.com:81/flight?${nothing}
return fetch(url).then((res) => res.json())
}