-
StateAirline Client part-2FE 2023. 5. 31. 20:40
Side Effect (부수 효과)
React에서 컴포넌트내에 fetch를 사용해 API 정보를 가져오거나 이벤트를 활용해 DOM 직접 조작할 때 발생
let foo = 'hello'; function bar() { foo = 'world'; } bar(); // bar는 Side Effect를 발생시킵니다!
Pure Function (순수 함수)
오직 함수의 입력만이 함수의 결과에 영향을 주는 함수. 입력으로 전달된 값을 수정하지 않음
function upper(str) { return str.toUpperCase(); // toUpperCase 메소드는 원본을 수정하지 않습니다 (Immutable) } upper('hello') // 'HELLO'
Effect Hook
useEffect는 컴포넌트 내에서 side effect를 실행할 수 있게 하는 Hook인데 Side effect는 브라우저 API를 이용하며, 타이틀을 변경하는 것이다.
API
useEffect(함수) 첫 번째 인자는 함수이다. useEffect(함수, [종속성1, 종속성2, ...])
함수가 실행될 때에는,
- 컴포넌트 생성 후 처음 화면에 렌더링을 표시할 때
- 컴포넌트에 새로운 props가 전달되며 렌더링
- 컴포넌트에 상태(state)가 바뀌며 렌더링
매번 새로운 컴포넌트가 렌더링 될 때 실행됨 (최상위에서만 호출하며, React 함수 내에서 호출한다)
두 번째 인자는 배열인데 이 배열은 조건을 담고 있음. 종속성 배열은 어떤 값의 변경이 일어날 때 의미하며 배열엔 어떤 값의 목록이 들어간다. 배열을 빈 배열로 할 경우 컴포넌트가 처음 생성될 때만 effect 함수가 실행됨. 처음 외부 API를 통해 리소스를 받아오고 더 이상 API 호출이 필요하지 않을 때 사용
AJAX 요청을 보낼 때
useEffect(() => { fetch(`http://서버주소/proverbs?q=${filter}`) .then(resp => resp.json()) .then(result => { setProverbs(result); }); }, [filter]);
엔드 포인트가 http://서버주소/proverbs일 경우.
AJAX 요청이 느릴 경우
외부 API 접속이 느릴 경우를 고려하여 로딩 화면의 구현은 필수이다. 상태처리 필요.
const [isLoading, setIsLoading] = useState(true); // 생략, LoadingIndicator 컴포넌트는 별도로 구현했음을 가정합니다 return {isLoading ? <LoadingIndicator /> : <div>로딩 완료 화면</div>}
useEffect(() => { setIsLoading(true); fetch(`http://서버주소/proverbs?q=${filter}`) .then(resp => resp.json()) .then(result => { setProverbs(result); setIsLoading(false); }); }, [filter]);
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를 이용합니다. 아래 구현은 완전히 삭제되어도 상관없습니다.// TODO: 아래 구현을 REST API 호출로 대체하세요.let params = `?departure=${filterBy.departure}&destination=${filterBy.destination}`
return fetch(`http://ec2-43-201-32-255.ap-northeast-2.compute.amazonaws.com/flight${params}`).then((response) => (response.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);// });}.then은 Promise와 짝궁이며 이걸 펼칠 수 있게 해주는 것임. then이 뭘 의미하는지 알고 싶을 때 console.log로 확인해보기
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';
export default function Main() {// 항공편 검색 조건을 담고 있는 상태const [condition, setCondition] = useState({departure: 'ICN',});const [flightList, setFlightList] = useState([]);const [isloading, setloading] = useState(false)
// 주어진 검색 키워드에 따라 condition 상태를 변경시켜주는 함수const search = ({ departure, destination }) => {if (condition.departure !== departure ||condition.destination !== destination) {console.log('condition 상태를 변경시킵니다');setCondition({departure, destination});
// TODO: search 함수가 전달 받아온 '항공편 검색 조건' 인자를 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; // 실행에는 전혀 지장이 없지만, 테스트를 위해 필요한 코드입니다. 이 코드는 지우지 마세요!
// TODO: Effeck Hook을 이용해 AJAX 요청을 보내보세요.// TODO: 더불어, 네트워크 요청이 진행됨을 보여주는 로딩 컴포넌트(<LoadingIndicator/>)를 제공해보세요.useEffect(() => {setloading(true);getFlight(condition).then((data) => setFlightList(data)).then(() => setloading(false))},[condition]) //condition이 바뀔 때마다 useEffect를 사용하겠다
// 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>{isloading ? <LoadingIndicator />: <FlightList list={flightList} />}</div>
<div className="debug-area"><Debug condition={condition} /></div><img id="logo" alt="logo" src="codestates-logo.png" /></main></div>);}useState를 사용해 false일 때, isloading과 재할당 할 수 있는 setloading을 주었다
useEffect에서 setloading은 로딩을 시작하고 getFlight함수의 출발지와 도착지, setFlightList로 전체 데이터 목록을 불러오고 마지막 .then으로 로딩을 끝나며 condition이 바뀔 때마다 useEffect를 사용하는 것을 말한다.
'FE' 카테고리의 다른 글
RefactorExpress (0) 2023.06.02 CORS (0) 2023.06.01 StateAirline Client part-1 (0) 2023.05.30 Postman (0) 2023.05.26 [HTTP/네트워크] 실습 (0) 2023.05.25