StatesAirline Client - Part 2

비트·2023년 5월 31일
0

CodeStates

목록 보기
38/54
post-thumbnail

Part 2: AJAX 요청



Side Effect는 useEffect에서 다루기


1. 검색 조건이 바뀔 때마다, FlightDataApigetFlight를 검색 조건과 함께 요청

2. getFlight의 결과를 받아, flightList 상태를 업데이트

3. 더이상, 컴포넌트 내 필터 함수 filterByCondition를 사용하지 않습니다.

4. 더이상, 하드코딩된 flightList JSON을 사용하지 않습니다 (초기값은 빈 배열로 둡니다)

5. 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를 호출하도록 바꾸기

1. 검색 조건과 함께 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초 시간동안 로딩중인 화면 표현이 가능하기때문에 구현 목적으로 넣어줌.

profile
Drop the Bit!

0개의 댓글