sprint - statesairline clients

FeelSoo·2022년 4월 24일
2

CodeStates

목록 보기
20/43
post-thumbnail





첫번째 테스트는 state & props를 활용한 useState 구문으로 해결할 수 있고, 두번째 테스트는 SideEffect ( 함수 내에서 어떤 구현이 함수 외부에 영향을 끼치는 경우 ex --- 지역변수가 전역변수를 변경시킬 때 ) 를 UseEffect 구문으로 해결한다.

UseEffect 활용에는 2가지 방법이 있다.

  1. 빈 배열 넣기
    useEffect(함수, [])

  2. 아무것도 넣지 않기 (기본 형태)
    useEffect(함수)

(2번) 기본 형태의 useEffect는 state가 업데이트 될 때마다 실행된다. 즉, 다중 실행된다.

반면에 (1번) 빈 배열을 useEffect의 두 번째 인자로 사용하면, 이 때에는 컴포넌트가 처음 생성될때만 effect 함수가 실행된다. 즉, 컴포넌트 생성시 1번 실행된다.

이것이 언제 필요할까? 대표적으로 처음 단 한 번, 외부 API를 통해 리소스를 받아오고 더이상 API 호출이 필요하지 않을 때에 사용할 수 있다. 즉, AJAX ( SPA 방식 ) 사용시에 적용할 수 있다.

정리하면 1번 방식을 쓸 때는 CSR 방식을 사용하는 것이고 2번 방식은 SSR 방식을 사용하는 것이다.


  • AJAX에 대해서는 SSR과 CSR의 포스트를 참고하면 이해가 빠를 것이다.

AJAX : Asynchronous JavaScript And XMLHttpRequest의 약자로, Fetch 모듈을 이용한다

AJAX의 가장 큰 특징은 웹 페이지에 필요한 부분에 필요한 데이터만 비동기적으로 받아와 화면에 그려낼 수 있다는 것

브라우저는 Fetch가 서버에 요청을 보내고 응답을 받을때까지 모든 동작을 멈추는 것이 아니라, 계속해서 페이지를 사용할 수 있게 만들어준다

링크텍스트 -- SSR & CSR

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 json from '../resource/flightList'

export default function Main() {
  const [condition, setCondition] = useState({    // condition의 초기값은 departure : 'ICN'이다. condition은 상태 변수이다
    departure: 'ICN'
  })
  const [flightList, setFlightList] = useState()  // 더이상, 하드코딩된 flightList JSON을 사용하지 않습니다 (초기값은 빈 배열로 둡니다)
  const [isLoading, setIsLoading ] = useState(false) // 로딩 상태 설정. 초기값은 false (isloading = false == 초기에는 로딩중이지 않다)

  const search = ({ departure, destination }) => {
    if (condition.departure !== departure || condition.destination !== destination) {  
      console.log('condition 상태를 변경시킵니다')
    
    setCondition({ departure, destination })      /// 상태를 변경시켜야 하므로 search의 인자 {departure, destination}를 받아 setCondition을 통해 
      // TODO:                                  /// condition을 변경시킨다
    }
  }

  useEffect(() => {    // 외부에서 호출한 값 (node.js 환경 )으로 내부 상태값 (react 환경 ) 을 변경시켜야 하니 Side Effect로 볼 수 있음. (로컬 함수의 제공값을 이용하는게 아니라 서버의 데이터를 이용함) Side Effect는 Effect Hook으로 처리
    setIsLoading(true) // useEffect가 호출되면 데이터를 받아와야 하니 false였던 isLoading 상태를 true로 변경시켜준다
    getFlight(condition) // import한 getFlight에서 condition 객체로 필터링을 진행하여 데이터를 추출한 후
    .then(data => {  // 그 데이터(departure, destination)를 이용해 Flightlist와 isloading의 상태를 변경시켜준다 
      setFlightList(data) // flightList에는 받아온 데이터를 넘겨주어 상태를 변경시켜주고
      setIsLoading(false)    //  데이터를 받아왔으니 로딩 화면도 종료시켜준다.
    })
  }, [condition]) // *useEffect의 두번째 인자 [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}/> {/*// 상태 변경 함수 `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)} /> 
          필터함수 삭제 & LoadingIndicator 사용 */}
          {isLoading ? <LoadingIndicator /> : <FlightList list ={flightList} /> /// 로딩중이면 로딩인디케이터, 아니면 FlightList의 list 항목 추출
          }
        </div>

        <div className="debug-area">
          <Debug condition={condition} />
        </div>
      </main>
    </div>
  )
}




Search.js


import { includeStack } from 'chai/lib/chai/config'
import { useState } from 'react'

function Search({onSearch}) { // 상태 변경 함수 `search`가 `onSearch` props로 전달되어야 합니다. 함수로 받기 위해 {}로 받음 주의?
  const [textDestination, setTextDestination] = useState('')
//const [textDeparture, setTextDeparture] = useState('')

  const handleChange = (e) => {                         /// 받아온 인자값을 대문자로 만든다
    setTextDestination(e.target.value.toUpperCase())
  }

//const handleChange2 = (e) => {
// setTextDeparture(e.target.value.toUpperCase())}

  const handleKeyPress = (e) => {                       // 엔터 버튼이 눌렸는지 감지하는 이벤트
    if (e.type === 'keypress' && e.code === 'Enter') {  // 키가 눌렸고 그게 엔터라면 핸들서치클릭을 실행
      handleSearchClick()
    }
  }

  const handleSearchClick = () => {
    console.log('검색 버튼을 누르거나, 엔터를 치면 search 함수가 실행됩니다')

    // TODO: 상태 변경 함수 `search`는 Search 컴포넌트의 `검색` 버튼 클릭 시 실행되어야 합니다 
    // search는 setCondition({ departure, destination })를 실행
    // 검색 버튼 클릭시 >> onClick >> {handleSearchClick}

    onSearch({departure : "ICN", destination : textDestination}) // 버튼이 클릭되면 onSearch의 값이 search 함수에게 전달되어 실행
  }

  return <fieldset>
    <legend>공항 코드를 입력하고, 검색하세요</legend>
    <span>출발지</span> {/* 출발지는 ICN 고정*/}
    <input id="input-departure" type="text" disabled value="ICN"></input>

    
    {/*<input id="input-departure" 
    type="text" 
    value={textDeparture}
    onChange={handleChange2}
    placeholder="CJU, BKK, PUS"
    onkeyPress={handleKeyPress}></input>
    이 코드는 departure를 ICN 고정을 해체하여 선택 변경 가능하게 만드는 코드. 위의 주석들과 같이 해체하고 기존의 코드를 주석처리하면 변경 가능.
    */}

    <span>도착지</span>  {/*도착지 입력란. 이벤트 함수는 3가지. handleSearchClick, handleChange, handleKeyPress */}
    <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를 이용합니다. 아래 구현은 완전히 삭제되어도 상관없습니다.
  // 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);
  // });



 // return fetch(url)가 필요한데 url에 들어갈 값은 필터링된 데이터의 값이다.

 
  let result = ''                                             // result 변수 선언
  if(filterBy.departure){                                     // filterBy.departure가 호출되면 즉 export한 getFlight이 호출되면 (Main 컴포 참고 --- getFlight(condition))
    result = result + `departure=${filterBy.departure}&`      // result에 필터링된 daparture를 json화시켜 저장
  }
  if(filterBy.destination){                                   // filterBy.destination이 호출되면 즉 export한 getFlight이 호출되면 (Main 컴포 참고 --- getFlight(condition))
    result = result + `destination=${filterBy.destination}`   // result에 필터링된 destination도 json화시켜 저장
  }
  let url = `http://ec2-13-124-90-231.ap-northeast-2.compute.amazonaws.com:81/flight?${result}`   // 필터링된 departure와 destination의 값을 담은 result를 명시한 url 설정

  return fetch(url)                 // url을 서버에 요청한다
    .then(res => res.json())        // 받아온 데이터를 json화 시켜 저장한다

}




profile
세상은 넓고 배울건 많다

0개의 댓글