ABOUT ME

Today
Yesterday
Total
  • [React] ์‹ค์Šต - StatesAirline Client
    codeStates front-end/React 2023. 2. 4. 16:52
    ๋ฐ˜์‘ํ˜•

     

     

    ๐Ÿ“Œ StatesAirline Client

     

     

     

    ๐Ÿ“– ํ•™์Šต ๋ชฉํ‘œ

     

    Part - 1

     

     

     

     

    [React] ๋ฐ์ดํ„ฐ ํ๋ฆ„

    ๐Ÿ“Œ๋ฆฌ์•กํŠธ ๋ฐ์ดํ„ฐ ํ๋ฆ„ ๐Ÿ“๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„( one-way data flow ) React๋Š” ํŽ˜์ด์ง€ ๋‹จ์œ„๊ฐ€ x -> ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  -> ํŽ˜์ด์ง€๋ฅผ ์กฐ๋ฆฝ (์ƒํ–ฅ์‹(bottom-up)์œผ๋กœ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ๋ฅผ ์ง ๋‹ค) ์ปดํฌ๋„Œ

    hwantech.tistory.com

     

    Part - 2

     

     

     

     

    [React] Effect Hook

    ๐Ÿ“ŒEffect Hook React ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋ฐ›์•„์˜ค๋Š” ๊ณผ์ • ๐Ÿ”—Side Effect (๋ถ€์ˆ˜ ํšจ๊ณผ) React์—์„œ ์ปดํฌ๋„Œํ‹‘ ๋‚ด์—์„œ fetch๋ฅผ ์‚ฌ์šฉํ•ด API ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ์ด๋ฒคํŠธ๋ฅผ ํ™œ์šฉํ•ด DOM ์ง์ ‘ ์กฐ์ž‘ํ• 

    hwantech.tistory.com

     

    Part 1 - Test

     

    • Main ์ปดํฌ๋„ŒํŠธ ๋‚ด search ํ•จ์ˆ˜๋Š” ๊ฒ€์ƒ‰ ์กฐ๊ฑด์„ ๋‹ด๊ณ  ์žˆ๋Š” ์ƒํƒœ ๊ฐ์ฒด condition์„ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค
      const search = ({ departure, destination }) => {
        if (
          condition.departure !== departure ||
          condition.destination !== destination
        ) {
          console.log('condition ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ต๋‹ˆ๋‹ค');
    
          // TODO: search ํ•จ์ˆ˜๊ฐ€ ์ „๋‹ฌ ๋ฐ›์•„์˜จ 'ํ•ญ๊ณตํŽธ ๊ฒ€์ƒ‰ ์กฐ๊ฑด' ์ธ์ž๋ฅผ condition ์ƒํƒœ์— ์ ์ ˆํ•˜๊ฒŒ ๋‹ด์•„๋ณด์„ธ์š”.
          
        }
      };

     

    condition์„ ์—…๋ฐ์ดํŠธ -> state์˜ ์ƒํƒœ๋ฅผ ๊ฐฑ์‹ ํ•ด์•ผํ•œ๋‹ค

    condition์˜ ์ดˆ๊ธฐ๊ฐ’์€ departure: 'ICN' ์ถœ๋ฐœ ์ •๋ณด๋งŒ ๋‹ด๊ฒจ ์žˆ์Œ

    ์ด ๋ง์€ ์ถœ๋ฐœ์ง€๋Š” ICN์œผ๋กœ ์ •ํ•ด์ ธ ์žˆ๊ณ  destination์€ ์ •ํ•ด์ง€์ง€ ์•Š์•˜๋‹ค

    ์ด๋ฅผ ์—…๋ฐ์ดํŠธ ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด์„  setCondition์œผ๋กœ condition ๊ฐ’์„ ๋ฐ”๊พธ์–ด ์ค˜์•ผ ํ•œ๋‹ค

     

      const search = ({ departure, destination }) => {
        if (
          condition.departure !== departure ||
          condition.destination !== destination
        ) {
          console.log('condition ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ต๋‹ˆ๋‹ค');
    
          // TODO: search ํ•จ์ˆ˜๊ฐ€ ์ „๋‹ฌ ๋ฐ›์•„์˜จ 'ํ•ญ๊ณตํŽธ ๊ฒ€์ƒ‰ ์กฐ๊ฑด' ์ธ์ž๋ฅผ condition ์ƒํƒœ์— ์ ์ ˆํ•˜๊ฒŒ ๋‹ด์•„๋ณด์„ธ์š”.
          setCondition({departure, destination})
        }
      };

     

     

    • Search ์ปดํฌ๋„ŒํŠธ์—๋Š” ์ƒํƒœ ๋ณ€๊ฒฝ ํ•จ์ˆ˜ search๊ฐ€ onSearch props๋กœ ์ „๋‹ฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค
    • ์ƒํƒœ ๋ณ€๊ฒฝ ํ•จ์ˆ˜ search๋Š” Search ์ปดํฌ๋„ŒํŠธ์˜ ๊ฒ€์ƒ‰ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์‹คํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

     

    ์ด ๋•Œ, ์ƒ๊ฐํ•ด์•ผํ•˜๋Š” ๋ถ€๋ถ„

     

     

     

    Parent Component -> main

    A Component -> search

     

    search ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์‹์ธ๋ฐ ๋ถ€๋ชจํ•œํ…Œ ์–ด๋–ป๊ฒŒ props๋ฅผ ์ „๋‹ฌํ•˜์ง€? ๋ถ„๋ช… ๋ถ€๋ชจ์—์„œ ์ „๋‹ฌํ•œ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ,,,

    ๐Ÿ‘‰๐Ÿป๐Ÿ‘‰๐Ÿป๐Ÿ‘‰๐Ÿป ์ด๋ฅผ ์ƒํƒœ ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ

     

    ์‚ฌ์‹ค์ƒ, search ํ•จ์ˆ˜์— ๋ชจ๋“  ๊ฒ€์ƒ‰๊ธฐ๋Šฅ์ด ๋“ค์–ด์žˆ์–ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€๋ถ€๋ถ„์ด ์ƒํƒœ๋“ค์ด

    search ํ•จ์ˆ˜์— ์ •์˜๋˜์–ด์žˆ๋‹ค ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ƒํƒœ ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ๋กœ main์œผ๋กœ ์ „๋‹ฌํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

     

    Search.js

     

    import { useState } from 'react';
    
    {/* Search ์ปดํฌ๋„ŒํŠธ์— onSearch๋ผ๋Š” props๋กœ searchํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•œ๋‹ค*/}
    function Search({onSearch}) {
      const [textDestination, setTextDestination] = useState('');

    Main.js

     

    return (
        <div>
          <Head>
            <title>States Airline</title>
            <link rel="icon" href="/favicon.ico" />
          </Head>
    
          <main>
            <h1>์—ฌํ–‰๊ฐ€๊ณ  ์‹ถ์„ ๋•, States Airline</h1>
            <Search onSearch={search}/>
            // ์ƒํƒœ ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ๋กœ props๋ฅผ ์ „๋‹ฌ
            <div className="table">
              <div className="row-header">
                <div className="col">์ถœ๋ฐœ</div>
                <div className="col">๋„์ฐฉ</div>
                ...(์ƒ๋žต)

     

    Part 2 - Test

     

     

    • ๊ฒ€์ƒ‰ ์กฐ๊ฑด์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค, FlightDataApi์˜ getFlight๋ฅผ ๊ฒ€์ƒ‰ ์กฐ๊ฑด๊ณผ ํ•จ๊ป˜ ์š”์ฒญํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค
    • getFlight์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„, flightList ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

     

    ๊ฒ€์ƒ‰ ์กฐ๊ฑด์ด ๋ฐ”๋€๋‹ค๋Š” ๊ฒƒ์€ -> ์ƒํƒœ๊ฐ€ ๋ณ€ํ•œ๋‹ค๋Š” ๊ฒƒ

    sideEffect ์ฒ˜๋ฆฌ, side effect๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด์„œ useEffect๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค

    getFilght ๊ฒฐ๊ณผ๋„ ๋ฐ›์•„ ๊ฐ™์ด ์—…๋ฐ์ดํŠธ 

     

      // TODO: Effeck Hook์„ ์ด์šฉํ•ด AJAX ์š”์ฒญ์„ ๋ณด๋‚ด๋ณด์„ธ์š”.
      // TODO: ๋”๋ถˆ์–ด, ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์ง„ํ–‰๋จ์„ ๋ณด์—ฌ์ฃผ๋Š” ๋กœ๋”ฉ ์ปดํฌ๋„ŒํŠธ(<LoadingIndicator/>)๋ฅผ ์ œ๊ณตํ•ด๋ณด์„ธ์š”.
      // useEffect(() => {
    
      useEffect(() => {
        getFlight(condition)
      }, [condition] 
      )

     

    • getFlight ์š”์ฒญ์ด ๋‹ค์†Œ ๋А๋ฆฌ๋ฏ€๋กœ, ๋กœ๋”ฉ ์ƒํƒœ์— ๋”ฐ๋ผ LoadingIndicator ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ‘œ์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

    ์™ธ๋ถ€ API๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์ ‘์†์ด ๋А๋ฆฐ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๊ธฐ์— ๋กœ๋”ฉํ™”๋ฉด ๊ตฌํ˜„์€ ํ•„์ˆ˜๋‹ค

    loading state ์ฒ˜๋ฆฌ ์ดˆ๊ธฐ๊ฐ’์€ ๋กœ๋”ฉ์ค‘์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— false๋ฅผ ์ฃผ์–ด์•ผํ•œ๋‹ค.

     

      // TODO: Effeck Hook์„ ์ด์šฉํ•ด AJAX ์š”์ฒญ์„ ๋ณด๋‚ด๋ณด์„ธ์š”.
      // TODO: ๋”๋ถˆ์–ด, ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์ง„ํ–‰๋จ์„ ๋ณด์—ฌ์ฃผ๋Š” ๋กœ๋”ฉ ์ปดํฌ๋„ŒํŠธ(<LoadingIndicator/>)๋ฅผ ์ œ๊ณตํ•ด๋ณด์„ธ์š”.
    
      const [isLoading, setIsLoading] = useState(false)
      // useEffect(() => {
    
      useEffect(() => {
        getFlight(condition)
      }, [condition] 
      )

     

    <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>
              //์ด์ œ api๋ฅผ ์ด์šฉํ•ด์„œ list๋ฅผ ๋ฐ›์„ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— filterByCondition๋Š” ์ฃผ์„ ์ฒ˜๋ฆฌ ํ•ด์ค€๋‹ค
              {/* <FlightList list={flightList.filter(filterByCondition)} /> */}
              // ๋กœ๋”ฉ์ค‘์ด๋ฉด LoadingIndicator ์ปดํฌ๋„ŒํŠธ, ๋กœ๋”ฉ์ค‘์ด ์•„๋‹ˆ๋ฉด flightList ์ปดํฌ๋„ŒํŠธ ์ถœ๋ ฅ
              {isLoading ? <LoadingIndicator /> : <FlightList list ={flightList } /> }
            </div>

     

    ๋กœ๋”ฉํ™”๋ฉด์ด ๋Œ์•„๊ฐˆ์ˆ˜ ์žˆ๋„๋ก useEffect์— ์ถ”๊ฐ€ ๊ตฌํ˜„

     

      useEffect(() => {
        setIsLoading(true); // getFlight๊ฐ€ ์‹คํ–‰ ๋˜๊ธฐ ์ „ ๋กœ๋”ฉํ™”๋ฉด
        getFlight(condition)
        .then((filter) => {
          setFlightList(filter)
          setIsLoading(false) // getFlight๊ฐ€ ์‹คํ–‰ ๋˜๊ธฐ ํ›„ ๋กœ๋”ฉํ™”๋ฉด
        })
      }, [condition] 
      )

     

     

    • ๊ฒ€์ƒ‰ ์กฐ๊ฑด๊ณผ ํ•จ๊ป˜ StatesAirline ์„œ๋ฒ„์—์„œ ํ•ญ๊ณตํŽธ ์ •๋ณด๋ฅผ ์š”์ฒญ(fetch)ํ•ฉ๋‹ˆ๋‹ค

     

    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 ํ˜ธ์ถœ๋กœ ๋Œ€์ฒดํ•˜์„ธ์š”.
      // fetch ๋ฅผ ์‚ฌ์šฉํ•ด ๋‹ค์‹œ ์ž‘์„ฑํ•œ๋‹ค 
      
      // fetch๋ฅผ ์ด์šฉํ•ด ์„œ๋ฒ„์— AJAX ์š”์ฒญ
    
      let emString = ''
      if(filterBy.departure){
        emString = emString + `departure=${filterBy.departure}&`
      }
      if(filterBy.destination){
        emString = emString + `destination=${filterBy.destination}`
      }
      let endpoint = `http://ec2-13-124-90-231.ap-northeast-2.compute.amazonaws.com:81/flight?${emString}`
    
      return fetch(endpoint)
        .then(res => res.json())
    }

     

    ์‚ฌ์‹ค ์ด ๋ถ€๋ถ„์€ ๋‚˜๋„ ์ •ํ™•ํ•˜๊ฒŒ๋Š” ๋จธ๋ฅด๊ฒ ๋‹น...ใ…Ž

    ๋ฐ˜์‘ํ˜•

    'codeStates front-end > React' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

    ๋Œ“๊ธ€

Designed by Tistory.