Jieunny์ ๋ธ๋ก๊ทธ
S2) Unit 9. [์ค์ต] StateAirline Client ๋ณธ๋ฌธ
๐ฃ Ajax๋ฅผ ํ์ฉํด์ ํญ๊ณตํธ ๊ฒ์ ํ์ด์ง ๊ตฌํํ๊ธฐ
1๏ธโฃ ํญ๊ณต๊ถ ๋ชฉ๋ก ํํฐ๋ง
โ๏ธ Main ์ปดํฌ๋ํธ์์ ํญ๊ณตํธ์ ์กฐํํ๋ค.
โฐ Main ์ปดํฌ๋ํธ ๋ด `search` ํจ์๋ ๊ฒ์ ์กฐ๊ฑด์ ๋ด๊ณ ์๋ ์ํ ๊ฐ์ฒด `condition`์ ์ ๋ฐ์ดํธํด์ผ ํ๋ค.
โ๏ธ Search ์ปดํฌ๋ํธ๋ฅผ ํตํด ์ํ ๋์ด์ฌ๋ฆฌ๊ธฐ๋ฅผ ํ์ตํ๋ค.
โฐ ๊ฒ์ ํ๋ฉด์ด Search ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌ๋์ด์ผ ํ๋ค.
โฐ Search ์ปดํฌ๋ํธ์๋ ์ํ ๋ณ๊ฒฝ ํจ์ `search`๊ฐ `onSearch` props๋ก ์ ๋ฌ๋์ด์ผ ํ๋ค.
โฐ ์ํ ๋ณ๊ฒฝ ํจ์ `search`๋ Search ์ปดํฌ๋ํธ์ `๊ฒ์` ๋ฒํผ ํด๋ฆญ ์ ์คํ๋์ด์ผ ํ๋ค.
2๏ธโฃ AJAX ์์ฒญ
โ๏ธ Side Effect๋ useEffect์์ ๋ค๋ค์ผ ํ๋ค.
โฐ ๊ฒ์ ์กฐ๊ฑด์ด ๋ฐ๋ ๋๋ง๋ค, FlightDataApi์ getFlight๋ฅผ ๊ฒ์ ์กฐ๊ฑด๊ณผ ํจ๊ป ์์ฒญํด์ผ ํ๋ค.
โฐ getFlight์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์, flightList ์ํ๋ฅผ ์ ๋ฐ์ดํธํด์ผ ํ๋ค.
โฐ ๋์ด์, ์ปดํฌ๋ํธ ๋ด ํํฐ ํจ์ `filterByCondition`๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค.
โฐ ๋์ด์, ํ๋์ฝ๋ฉ๋ flightList JSON์ ์ฌ์ฉํ์ง ์๋๋ค. (์ด๊ธฐ๊ฐ์ ๋น ๋ฐฐ์ด๋ก ๋๋ค.)
โฐ getFlight ์์ฒญ์ด ๋ค์ ๋๋ฆฌ๋ฏ๋ก, ๋ก๋ฉ ์ํ์ ๋ฐ๋ผ LoadingIndicator ์ปดํฌ๋ํธ๋ฅผ ํ์ํด์ผ ํ๋ค.
โ๏ธ FlightDataApi์์ ๊ธฐ์กด ๊ตฌํ ๋์ , REST API๋ฅผ ํธ์ถํ๋๋ก ๋ฐ๊พผ๋ค.
โฐ ๊ฒ์ ์กฐ๊ฑด๊ณผ ํจ๊ป StatesAirline ์๋ฒ์์ ํญ๊ณตํธ ์ ๋ณด๋ฅผ ์์ฒญ(fetch)ํ๋ค.
๐ก 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๋ฅผ ์ญ์ ํฉ๋๋ค.
export default function Main() {
// ํญ๊ณตํธ ๊ฒ์ ์กฐ๊ฑด์ ๋ด๊ณ ์๋ ์ํ
const [condition, setCondition] = useState({
departure: 'ICN',
});
const [flightList, setFlightList] = useState();
const [loading, setLoading] = useState(false);
// ๋ก๋ฉ ํ์ด์ง ๋์ฐ๊ธฐ ์ํด์ ๋ก๋ฉ ์ค์ธ์ง ์๋์ง ๋ด๊ณ ์๋ state
// ์ฃผ์ด์ง ๊ฒ์ ํค์๋์ ๋ฐ๋ผ condition ์ํ๋ฅผ ๋ณ๊ฒฝ์์ผ์ฃผ๋ ํจ์
const search = ({ departure, destination }) => {
if (
condition.departure !== departure ||
condition.destination !== destination
) {
console.log('condition ์ํ๋ฅผ ๋ณ๊ฒฝ์ํต๋๋ค');
setCondition({departure, destination});
// ์ํ ๋ณ๊ฒฝ ํจ์๋ฅผ ์ฌ์ฉํด์ condition ์ ๋ณ๊ฒฝ์ํจ๋ค.
// TODO: search ํจ์๊ฐ ์ ๋ฌ ๋ฐ์์จ 'ํญ๊ณตํธ ๊ฒ์ ์กฐ๊ฑด' ์ธ์๋ฅผ condition ์ํ์ ์ ์ ํ๊ฒ ๋ด์๋ณด์ธ์.
}
};
global.search = search; // ์คํ์๋ ์ ํ ์ง์ฅ์ด ์์ง๋ง, ํ
์คํธ๋ฅผ ์ํด ํ์ํ ์ฝ๋์
๋๋ค. ์ด ์ฝ๋๋ ์ง์ฐ์ง ๋ง์ธ์!
// TODO: Effeck Hook์ ์ด์ฉํด AJAX ์์ฒญ์ ๋ณด๋ด๋ณด์ธ์.
// TODO: ๋๋ถ์ด, ๋คํธ์ํฌ ์์ฒญ์ด ์งํ๋จ์ ๋ณด์ฌ์ฃผ๋ ๋ก๋ฉ ์ปดํฌ๋ํธ(<LoadingIndicator/>)๋ฅผ ์ ๊ณตํด๋ณด์ธ์.
useEffect(() => { // ํญ๊ณตํธ์ ๊ฒ์ํ์ ๋, ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์์ ๋ถ๋ฌ์จ๋ค. -> ๋ถ๋ฌ์ค๋ ๋์ ๋ก๋ฉ์ฐฝ ๋์ฐ๊ธฐ
setLoading(true); // ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ ๋์ ๋ก๋ฉ์ฐฝ์ ๋์ฐ๊ธฐ ์ํด์ true๋ก ๋ฐ๊ฟ์ค๋ค.
getFlight(condition).then((flights) => {
// ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ getFlight ํจ์๋ฅผ ํธ์ถํ๋ค.
//fetch๋ Promise๋ฅผ ๋ฐํํ๋ฏ๋ก .then์ผ๋ก ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ flights์ ๋ด๋๋ค.
setFlightList(flights);
setLoading(false);
});
}, [condition])
// 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>
{/* <FlightList list={flightList.filter(filterByCondition)} /> */}
{ loading ? <LoadingIndicator /> : <FlightList list={flightList} />}
</div>
<div className="debug-area">
<Debug condition={condition} />
</div>
<img id="logo" alt="logo" src="codestates-logo.png" />
</main>
</div>
);
}
๐ก Search.js
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});
// props๋ก ๋ฐ์ onSearch์๋ search ํจ์๊ฐ ๋ค์ด์์ผ๋ฏ๋ก ๊ฒ์ ๋ฒํผ์ ๋๋ฅด๋ฉด search ํจ์๊ฐ ์คํ๋๋ค.
// 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.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 = {}) {
// HINT: ๊ฐ์ฅ ๋ง์ง๋ง ํ
์คํธ๋ฅผ ํต๊ณผํ๊ธฐ ์ํด, fetch๋ฅผ ์ด์ฉํฉ๋๋ค. ์๋ ๊ตฌํ์ ์์ ํ ์ญ์ ๋์ด๋ ์๊ด์์ต๋๋ค.
let query = '';
if(filterBy.departure){
query = query + `departure=${filterBy.departure}&`;
}
// Search.js ์์ getFlight๋ฅผ ๋ถ๋ฅผ ๋, departure์ destination ์ด ๋ด๊ธด ๊ฐ์ฒด๋ฅผ ์ธ์๋ก ์ฃผ์์ผ๋ฏ๋ก,
// filterBy์๋ ๊ทธ ์ธ์๊ฐ ๋ค์ด์๋ค.
// endpoint์ ์ ๋ฌํด ์ค query๋ฅผ ๋ง๋ค์ด์ค๋ค.
if(filterBy.destination){
query = query + `destination=${filterBy.destination}`;
}
let endpoint = `http://ec2-13-124-90-231.ap-northeast-2.compute.amazonaws.com:81/flight?${query}`;
// fetch๋ url์ ์ธ์๋ก ๋ฐ์ผ๋ฏ๋ก endpoint๋ฅผ ๋ง๋ค์ด์ค์ fetch์ ์ ๋ฌํ๋ค.
return fetch(endpoint).then((res) => res.json());
}
๐ฃ ์์ฐ ํ๋ฉด
'CodeStates > Training' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
S2) Unit 10. [์ค์ต] StatesAirline Server (0) | 2023.02.08 |
---|---|
S2) Unit 10. [์ค์ต] Mini Node Server (0) | 2023.02.06 |
S2) Unit 6. [์ค์ต] React Twittler State & Props (0) | 2023.01.27 |
S2) Unit3. [์ค์ต] fetch API (0) | 2023.01.19 |
S2) Unit3. [์ค์ต] fs ๋ชจ๋ (0) | 2023.01.19 |