티스토리 뷰

3. 스크립트

Airport.js

패스트코드블로그 2020. 7. 23. 15:48

 

연습을 위한 템플릿만 제공합니다. 이 내용은 JSX 가 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<div style={{ outline: 'none', border: 0 }}>
      {loading === false &&
        <div style={{ outline: 'none', border: 0 }}>
          <div style={{ width: '100%', display: 'block' }}>
            <input
              type="text"
              placeholder="Enter Airport Name, Code or City Name"
              className="Search"
              // value={keyword}
              onChange={e => handleInput(e)} />
          </div>
          <div className="Gap"></div>
 
          <h5 style={{ marginTop: 10, marginBottom: 10, fontSize: 15, color: '#f0ad4e', textAlign: 'center' }}>
            {resultAvailable === true && "Search Results"}
            {selected === true && "Selected Airport"}
          </h5>
          {selected === true &&
            <div className="Results">
              <div style={{ marginTop: 0, padding: 10 }} onClick={() => setSelected(true)}>
                <div style={{ width: '100%', display: 'block' }}>
                  <span style={{ fontWeight: 'bold' }}>{airport.city}</span>
                  <span style={{ float: 'right' }}>{airport.iata}</span>
                </div>
                <p style={{ marginTop: 5, marginBottom: 0, paddingBottom: 5, color: '#777', borderBottom: '0.5px solid #9997' }}>{airport.airport}</p>
              </div>
            </div>
          }
          {selected === false && resultAvailable === true && airports.map((item, i) => (
            <div className="Results" key={i}>
              <div style={{ marginTop: 0, padding: 10 }} id="Select" onClick={() => selectAirport(item)}>
                <div style={{ width: '100%', display: 'block' }}>
                  <span style={{ fontWeight: 'bold' }}>{item.city}</span>
                  <span style={{ float: 'right' }}>{item.iata}</span>
                </div>
                <p style={{ marginTop: 5, marginBottom: 0, paddingBottom: 5, color: '#777', borderBottom: '0.5px solid #9997' }}>{item.airport}</p>
              </div>
            </div>
          ))
          }
        </div>
      }
    </div>
cs

 

해당 템플릿에 관련한 CSS 파일입니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
.Search {
  font-size: 16px;
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  display: block;
  margin-right: auto;
  margin-left: auto;
}
 
.Search:focus {
  border: 2px solid #666666;
  outline: none;
}
 
.Gap {
  border: 0px;
  background-color: #fff;
}
 
@media only screen and (max-width: 767px) {
  .Search {
    width: 92%;
    padding: 4%;
    border: 0px;
    box-shadow: 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);
  }
 
  .Search:focus {
    border: 0px;
    outline: none;
  }
 
  .Gap {
    margin-bottom: 55px;
  }
 
  .Results {
    width: 100%;
    border: 0px;
  }
}
 
@media only screen and (min-width: 768px) {
  .Search {
    width: 75%;
    padding: 15px;
    margin-top: 10px;
    border: 2px solid #999999;
    border-radius: 4px;
  }
 
  .Gap {
    margin-bottom: 65px;
  }
 
  .Results {
    width: 75%;
    margin-top: 10px;
    border: 0px;
    display: block;
    margin-right: auto;
    margin-left: auto;
  }
}
 
#Select:hover {
  background-color: #eeeeee
}
cs

 

최종 파일 입니다. 덕 패턴을 사용해서 원페이지로 마무리합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import React,{useState, useEffect} from "react";
import {useSelector, useDispatch} from "react-redux";
import { debounce } from 'throttle-debounce'
import axios from 'axios'
import './airport.css'
 
export const getAirports = data => ({type: "FETCH_AIRPORT", payload: data})
 
export const airportReducer = (state = [], action) =>{
    switch (action.type) {
        case "FETCH_AIRPORT"return action.payload
        defaultreturn state
    }
}
export const airportSearch = () => dispatch => {
    axios.get(`https://argodeep.github.io/React-Redux-Hooks-with-axios-redux-thunk/airport.json`)
        .then(response => {
            dispatch(getAirports(response.data))
        })
        .catch(error => {throw (error)})
}
 
 
const Airport = () => {
    const [loading , setLoading] = useState(false)
    const [resultAvailable, setResult] = useState(false)
    const [selected, setSelected] = useState(false)
    const [airport, setAirport] = useState({})
    const [airports, setAirports] = useState([])
    const handleInput = e =>{ searchAirports(e.target.value.trim().toLowerCase())}
    const selectAirport = payload => {
        setSelected(true)
        setResult(false)
        setAirport({airport: payload.airport, city: payload.city, iata: payload.iata})
    }
    const results = useSelector(state => state.airportReducer)
    const dispatch = useDispatch()
 
    useEffect(()=>{
        if(!results.data) fetch()
        else
            if(results.data.length > 0) changeTitle()
        if(airport.city !== undefined) changeTitle()
    })
    let fetch = () => dispatch(airportSearch())
    let fetched = () => setLoading(false)
    let changeTitle = () => document.title = `공항 검색 결과: ${airport.airport}`
    let searchAirports = debounce(500, input => {
        let data = results.data
        if(input.length < 0) alert(` Error `)
        switch (input.length) {
            case 0:
                setAirports([])
                setResult(false)
                setSelected(false)
                break
            case 1:
                setAirports(data.filter(
                    e => e.airport.charAt(0).toLowerCase()=== input.toLowerCase()
                    || e.city.toLowerCase().includes(input.toLowerCase())
                    || e.iata.toLowerCase().includes(input.toLowerCase())))
                setResult(true)
                break
            default:
                setAirports(data.filter(
                    e => e.airport.toLowerCase().includes(input.toLowerCase())
                    || e.city.toLowerCase().includes(input.toLowerCase())
                    || e.iata.toLowerCase().includes(input.toLowerCase())))
                setResult(true)
                break
        }
 
    })
 
    return <>
        <div style={{ outline: 'none', border: 0 }}>
            {loading === false &&
            <div style={{ outline: 'none', border: 0 }}>
                <div style={{ width'100%', display: 'block' }}>
                    <input
                        type="text"
                        placeholder="Enter Airport Name, Code or City Name"
                        className="Search"
                        // value={keyword}
                        onChange={e => handleInput(e)} />
                </div>
                <div className="Gap"></div>
 
                <h5 style={{ marginTop: 10, marginBottom: 10, fontSize: 15, color: '#f0ad4e', textAlign: 'center' }}>
                    {resultAvailable === true && "Search Results"}
                    {selected === true && "Selected Airport"}
                </h5>
                {selected === true &&
                <div className="Results">
                    <div style={{ marginTop: 0, padding: 10 }} onClick={() => setSelected(true)}>
                        <div style={{ width'100%', display: 'block' }}>
                            <span style={{ fontWeight: 'bold' }}>{airport.city}</span>
                            <span style={{ float: 'right' }}>{airport.iata}</span>
                        </div>
                        <p style={{ marginTop: 5, marginBottom: 0, paddingBottom: 5, color: '#777', borderBottom: '0.5px solid #9997' }}>{airport.airport}</p>
                    </div>
                </div>
                }
                {selected === false && resultAvailable === true && airports.map((item, i) => (
                    <div className="Results" key={i}>
                        <div style={{ marginTop: 0, padding: 10 }} id="Select" onClick={() => selectAirport(item)}>
                            <div style={{ width'100%', display: 'block' }}>
                                <span style={{ fontWeight: 'bold' }}>{item.city}</span>
                                <span style={{ float: 'right' }}>{item.iata}</span>
                            </div>
                            <p style={{ marginTop: 5, marginBottom: 0, paddingBottom: 5, color: '#777', borderBottom: '0.5px solid #9997' }}>{item.airport}</p>
                        </div>
                    </div>
                ))
                }
            </div>
            }
        </div>
    </>
}
export default Airport
cs

 

실행할 index.js 입니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './airport/Airport';
import * as serviceWorker from './serviceWorker';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import {Provider} from'react-redux'
import { combineReducers } from "redux";
import { airportReducer } from './airport/Airport'
 
const rootReducer = combineReducers({
    airportReducer
})
 
ReactDOM.render(
  <Provider store = {createStore(rootReducer, applyMiddleware(thunk))}>
    <App />
  </Provider>,
  document.getElementById('root')
);
 
serviceWorker.unregister();
 
cs

 

결과에 seoul 을 입력합니다.

 

이번에는 london 을 입력합니다. 결과가 길어서 이하 중단합니다.

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함