[22.06.30]

김도훈·2022년 6월 30일
0

동기와 비동기

동기

작업(task)들이 순차적으로 이루어 지는 것
다른 작업들을 blocking

비동기

잡업(task)들이 순차적으로 이루어지지 않음
다른 작업들은 non-blocking
Javascript를 사용한 비동기 통신 방식을 Ajax(Asynchronous Javascript and XML)
Http요청(GET, POST), 이벤트 핸들러(click, over …), setTimeout, setInterval

비동기 요소

Callback
콜백 함수란 인자로 들어오는 함수를 말함
콜백은 비동기 통신을 할 수 있는 패턴
문제점: 콜백 헬로 인한 에러처리 불가, 가독성 저하

날씨 API 실습

App.js
import logo from './logo.svg';
import './App.css';
import WeatherBox from './components/WeatherBox';
import WeatherButton from './components/WeatherButton';
import {Container} from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css'

function App() {
return (

  <div></div>
  <div className = "main-container">
    <WeatherBox />
    <WeatherButton />
  </div>
</Container>

);
}

export default App;
WeatherBox.js
import React from 'react'

const WeatherBox = () => {
return (

<div>
  <h3>대구</h3>
  <h3>33도/화씨 230도</h3>
  <h3>더움</h3>
</div>

);
}

export default WeatherBox;
WeatherButton.js
import React from 'react'

const WeatherButton = () => {
return (

<div>WeatherButton</div>

);
}

export default WeatherButton;
App.css
body {
background: url("https://images.unsplash.com/photo-1514454529242-9e4677563e7b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80");
height: 100vh;
background-repeat: no-repeat;
background-size: cover;
}

.main-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 300px;
text-align: center;
}

App.js API 불러오기
import React, { useState, useEffect } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import './App.css';
import { Container } from 'react-bootstrap';
import WeatherButton from './components/WeatherButton';
import WeatherBox from './components/WeatherBox';
import { ClipLoader } from 'react-spinners';

const cities = ['paris', 'new york', 'tokyo', 'seoul'];
const API_KEY = 'b4a0b63fb0a27cc709f6ea5ecd5f5d7d';

const App = () => {
const [loading, setLoading] = useState(false);
const [city, setCity] = useState(null);
const [weather, setWeather] = useState(null);
const [apiError, setAPIError] = useState('');

const getWeatherByCurrentLocation = async (lat, lon) => {
console.log('현재 위치', lat, lon);
//비동기 처리
try {
let url = //units=metric 캘빈을 섭씨로
// let url = https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY};
// https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY};
'http://api.openweathermap.org/data/2.5/weather?lat=35.87222&lon=128.60250&appid=b4a0b63fb0a27cc709f6ea5ecd5f5d7d';
//&units=metric
const res = await fetch(url);
const data = await res.json();
setWeather(data);
setLoading(false);
} catch (err) {
setAPIError(err.message);
setLoading(false);
}
};

const getCurrentLocation = () => {
navigator.geolocation.getCurrentPosition((position) => {
const { latitude, longitude } = position.coords;
getWeatherByCurrentLocation(latitude, longitude);
// console.log('현재 위치', lat, lon);
});
};

const getWeatherByCity = async () => {
try {
let url = https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY};
//&units=metric
const res = await fetch(url);
const data = await res.json();

  setWeather(data);
  setLoading(false);
} catch (err) {
  console.log(err);
  setAPIError(err.message);
  setLoading(false);
}

};

useEffect(() => {
if (city == null) {
setLoading(true);
getCurrentLocation();
} else {
setLoading(true);
getWeatherByCity();
}
}, [city]);

const handleCityChange = (city) => {
if (city === 'current') {
setCity(null);
} else {
setCity(city);
}
};

return (

{loading ? (

    <div className="w-100 vh-100 d-flex justify-content-center align-items-center">
      <ClipLoader color="#f86c6b" size={150} loading={loading} />
    </div>
  ) : !apiError ? (
    <div class="main-container">
      <WeatherBox weather={weather} />
      <WeatherButton
        cities={cities}
        handleCityChange={handleCityChange}
        selectedCity={city}
      />
    </div>
  ) : (
    apiError
  )}
</Container>

);
};

export default App;

App.css
body {
background: url('https://t4.ftcdn.net/jpg/04/97/80/99/360_F_497809944_FMo3DO6j7XSlb9rZKOlnqaaWoJhuZXBm.jpg');
height : 100vh;
background-repeat: no-repeat;
background-size: cover;
}

.weather-card{
background-color: rgba(52,52,52,.7);
padding: 50px;
border: 2px solid #fff;
border-radius: 20px;
max-width: 700px;
width:100%;
height: 300px;
}
.main-container{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;

}
.menu-container{
display: flex;
justify-content: center;
background-color: #000;
border-radius: 60px;
max-width: 700px;
width:100%;
padding: 30px;
margin-top: 30px;

}
.menu-container Button{
margin-right:30px;
}

.menu-container Button:hover{
background-color: #ffc107;
}
PublicNavbar.js
import React from 'react';
import { Navbar, Nav } from 'react-bootstrap';

const PublicNavbar = () => {
return (

<Navbar.Brand></Navbar.Brand>

  <Nav className="mr-auto"></Nav>
  <Nav>
    <a
      href="https://github.com/dhminh1024/cs_weather_app"
      target="_blank"
      rel="noreferrer"
    ></a>
  </Nav>
</Navbar>

);
};

export default PublicNavbar;
Weather.js
import React from 'react';
import { Card } from 'react-bootstrap';

const WeatherBox = ({ weather }) => {
const temperatureC =
weather && weather.main ? (weather.main.temp - 273.15).toFixed(2) : '';
const temperatureF =
weather && weather.main
? (((weather.main.temp - 273.15) 9) / 5 + 32).toFixed(2)
: '';
return (

{/
<Card.Img src="holder.js/100px270" alt="Card image" /> */}
<Card.ImgOverlay className="d-flex flex-column justify-content-center text-center">
<Card.Title>{weather?.name}</Card.Title>
<Card.Text className="text-success h1">
{${temperatureC} °C / ${temperatureF} °F}
</Card.Text>
<Card.Text className="text-info text-uppercase h2">
{weather && weather.weather[0]?.description}
</Card.Text>
</Card.ImgOverlay>

);
};

export default WeatherBox;
WeatherButton.js
import React from 'react';
import { Button } from 'react-bootstrap';

const WeatherButton = ({ cities, selectedCity, handleCityChange }) => {
return (

<div class="menu-container">
  <Button
    variant={`${selectedCity === null ? 'outline-warning' : 'warning'}`}
    onClick={() => handleCityChange('current')}
  >
    Current Location
  </Button>

  {cities.map((city) => (
    <Button
      variant={`${selectedCity === city ? 'outline-warning' : 'warning'}`}
      onClick={() => handleCityChange(city)}
    >
      {city}
    </Button>
  ))}
</div>

);
};

export default WeatherButton;

0개의 댓글