날씨 정보를 API로 가져와 react로 날씨앱 구현하기
1) API란?
Application Programming Interface(애플리케이션 프로그램 인터페이스)의 줄임말.
인터페이스는 두 애플리케이션 간의 서비스 계약이라고 할 수 있으며, 이 계약은 요청과 응답을 사용하여 두 애플리케이션이 서로 통신하는 방법을 정의합니다. API 문서에는 개발자가 이러한 요청과 응답을 구성하는 방법에 대한 정보가 들어 있다.
프로토콜 집합을 사용하여 두 소프트웨어 구성 요소가 서로 통신할 수 있게 하는 메커니즘이다.
2) 날씨앱 구현
3) 구현 내용
1.앱이실행되자마자현재위치기반의날씨가보인다.
2.날씨정보에는도시, 섭씨, 화씨, 날씨상태
3.5개의버튼이있다.(1개는현재위치, 4개는다른도시)
4.도시버튼을클릭할때마다도시별날씨가나온다.
5.현재위치버튼을누르면다시현재위치기반의날씨가나온다.
6.데이터를들고오는동안로딩스피너가돈다.
4) 구현을 위해 필요한 함수
Callback
Promise
then
과 catch
finally
async/await
4) 구현 코드
UI는 부트스크랩을 이용하여 구현을 하였다.
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 ( <Container className="vh-100"> {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;
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 className="weather-card">
{/* <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>
</Card>
);
};
export default WeatherBox;
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;
import React from 'react';
import { Navbar, Nav } from 'react-bootstrap';
const PublicNavbar = () => {
return (
<Navbar bg="light" expand="lg" className="position-fixed navbar-fixed">
<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;