0630
** 현재 위치 가져오기
• Geolocation API
https://www.w3schools.com/html/html5_geolocation.asp
• 검색 get current location javascript
HTML Geolocation API (w3schools.com)
• 검색 react-spinner
react-spinners - npm (npmjs.com)
• 검색 react-bootstrap
React-Bootstrap · React-Bootstrap Documentation
** 동기
** 비동기
•stateful 컴포넌트 : 모든 state를 들고있는 컴포넌트
•stateless 컴포넌트: state를 안들고 있고 props 와 같이 받은 데이터만 보여주는 컴포넌트
•리액트는 단방향 통신이다 즉 부모에서 자식으로만 데이터를 전달 할 수 있다.
이를통해 데이터 흐름을 추적하기는 더 쉽지만, 같은 형제끼리 데이터를 주고받기는 힘들다. 그래서 데이터는 주로 부모가 들고있고 자식에게
전달해주는 형식이 된다.
state를 들고있는 부모 컴포넌트는 stateful 컴포넌트, 부모가주는 데이터만 받는 컴포넌트를 stateless 컴포넌트라고 한다.
이렇게 컴포넌트를 구성하면 장점은 state가 없는 stateless컴포넌트는 재사용이 쉽고 데이터를 걱정하지 않아도 된다.
•모든 중요한 데이터들은 stateful컴포넌트에 있기 때문에 유지보수가 쉽다 (stateful컴포넌트 하나만 주시하고 관리해주면 되니까)
그래서 최대한 모든 컴포넌트를 stateless로 만들고 몇개의 stateful컴포넌트에서 데이터를 관리하는 구조가 이상적이라고 리액트는 말하고 있다.
https://openweathermap.org/api 미리 회원가입 API키 받아놓기
(vs코드 확장 들어가서) es7 react 설치
(WeatherBox.js 가서 rafc 치고 엔터
치면 함수형태로 자동완성됨)
npx create-react-app weather (폴더 생성)
cd weather (폴더 접속)
*터미널에서 부트스트랩 설치 명령어 (다시,매번 해줘야 되나?)
npm install react-bootstrap bootstrap
*터미널에서 react spinner 설치
npm install --save react-spinners
App.js
// import logo from './logo.svg';
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', 'newyork', 'tokyo', 'seoul'];
const API_KEY = '1c43ec90c2c7f5c2d8ab827dfe746ff5';
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) => {
// try{
// let url =`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}`;
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=1c43ec90c2c7f5c2d8ab827dfe746ff5';
//&units=metric
const res = await fetch(url);
const data = await res.json();
setWeather(data);
setLoading(false);
} catch (err) {
console.log(err.message);
setLoading(false);
}
};
const getCurrentLocation = () => {
navigator.geolocation.getCurrentPosition((position) => {
const { latitude, longitude } = position.coords;
getWeatherByCurrentLocation(latitude, longitude);
// console.log('현재위치?', latitude, longitude);
});
};
const getWeatherByCity = async () => {
try {
let url = 'http://api.openweathermap.org/data/2.5/weather?lat=35.87222&lon=128.60250&appid=1c43ec90c2c7f5c2d8ab827dfe746ff5';
//&units=metric
const res = await fetch(url);
const data = await res.json();
setWeather(data);
setLoading(false);
} catch (err) {
console.log(err);
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;
App.css
body {
background: url(https://img.freepik.com/free-vector/blue-cloudy-daylight-background-for-weather-design_33099-512.jpg?w=740&t=st=1656552925~exp=1656553525~hmac=2d002d18c9bbab5cc5db6dc6bc88087fe09525e283dc37e376582a715d4ad50b);
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;
}
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 className="weather-card">
<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;
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;
PublicNavbar.js
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;
다 어렵다.
어렵다.
이게 무슨 초급반 강의야..