< 완성본 >
프로젝트에서 OpenWeather API를 사용하여 날씨 웹사이트 맡아 만들었다.
기본적으로 Seoul의 날씨가 나오고 도시를 영어로 검색하면 검색한 도시의 날씨가 나온다.
서울의 날씨를 출력하는 js파일, 검색한 도시의 날씨를 출력하는 js파일을 별개로 만들었기 때문에
처음에는 서울의 날씨를 출력하고 검색버튼을 누르면 검색한 도시를 출력하는 js파일로 넘어가도록 만들었다.
도시 검색 부분에서 자세히 다루겠다.
OpenWeather API에 들어가서 회원가입을 하고 로그인을 한다.
로그인을 하면 API key를 받을 수 있다. 이 key를 저장해 두었다가 사용하면 된다.
API와 Pricing에 들어가보면 무료로 사용할 수 있는 버전과 유료로 사용할 수 있는 버전이 나온다.
본인이 원하는 버전으로 사용하면 된다.
나는 Current Weather Data, 5 Day / 3 Hour Forecast를 사용하였다.
API doc을 눌러보면 이 API를 어떻게 사용하는 지 방법이 나와있다.
< 배너 >
1. 날씨 API 가져오기
//API Call
https://api.openweathermap.org/data/2.5/weather?q= {city name}&appid={API key}
url에 들어가보면 이런 정보가 뜨는데 모두 복사하여 json파일로 저장해 두면 보기가 편하다.
{
"coord": { "lon": 126.9778, "lat": 37.5683 },
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04n"
}
],
"base": "stations",
"main": {
"temp": 295.04,
"feels_like": 295.9,
"temp_min": 294.91,
"temp_max": 295.84,
"pressure": 1009,
"humidity": 100
},
"visibility": 10000,
"wind": { "speed": 1.03, "deg": 130 },
"clouds": { "all": 75 },
"dt": 1693319344,
"sys": {
"type": 1,
"id": 8105,
"country": "KR",
"sunrise": 1693256359,
"sunset": 1693303659
},
"timezone": 32400,
"id": 1835848,
"name": "Seoul",
"cod": 200
}
axios를 이용하여 날씨를 가져왔다.
무료버전이라 요청을 많이 하면 429 오류가 나므로 오류메시지를 console로 띄우게 했다.
//SeoulWeather.js
const [weather, setWeather] = useState({});
const url = `https://api.openweathermap.org/data/2.5/weather?q=Seoul&appid=개인APIkey`;
// 날씨 가져오기
useEffect(() => {
axios
.get(url)
.then(responseData => {
const data = responseData.data;
setWeather({
id: data.weather[0].id,
main: data.weather[0].main, //날씨
temperature: data.main.temp, //온도
temp_max: data.main.temp_max, //최고온도
temp_min: data.main.temp_min, //최저온도
feels_like: data.main.feels_like, //체감온도
humidity: data.main.humidity, //습도
wind: data.wind.speed, //바람
clouds: data.clouds.all, //구름
loading: false,
});
})
.catch(error => {
if (error.response && error.response.status === 429) {
console.error('많은 요청으로 오류가 발생합니다. 잠시 기다려주세요.');
}
});
}, [url]);
2. 날짜 표시
//SeoulWeather.js
function convertDate(milliSecond) {
const date = new Date(milliSecond * 1000); //Date객체 생성
const year = date.getFullYear(); //년도 가져오기
const month = date.getMonth() + 1; //월은 0부터 시작하므로 +1
const day = date.getDate(); //일 가져오기
const hour = date.getHours(); //시간 가져오기
const min = date.getMinutes(); //분 가져오기
return `${year}.${month}.${day} ${hour}시 ${min}분`;
}
3. 배경 이미지
날씨에 따라 배경 이미지를 변하게 하기 위해 함수를 정의하였다.
id를 받아와서 id에 따라 이미지를 다르게 넣었다.
//SetBackground.js
import Clear from './BackgroundImg/Clear.jpg';
import Clouds from './BackgroundImg/Clouds.jpg';
import Drizzle from './BackgroundImg/Drizzle.jpg';
import Mist from './BackgroundImg/Mist.jpg';
import Rain from './BackgroundImg/Rain.jpg';
import Snow from './BackgroundImg/Snow.jpg';
import Thunderstorm from './BackgroundImg/Thunderstorm.jpg';
import CloudSun from './BackgroundImg/CloudSun.jpg';
export default function SetBackground(id) {
let imgId = id === 800 ? 0 : (parseInt(id) / 100).toFixed(0);
switch (imgId) {
case 0:
return <img src={Clear} alt="맑음" no-repeat="true" />;
case '2':
return <img src={Thunderstorm} alt="뇌우" no-repeat="true" />;
case '3':
return <img src={Drizzle} alt="이슬비" no-repeat="true" />;
case '5':
return <img src={Rain} alt="비" no-repeat="true" />;
case '6':
return <img src={Snow} alt="눈" no-repeat="true" />;
case '7':
return <img src={Mist} alt="옅은 안개" no-repeat="true" />;
case '8':
return <img src={Clouds} alt="흐림" no-repeat="true" />;
default:
return <img src={CloudSun} alt="기본" no-repeat="true" />;
}
}
4. 날씨 아이콘
배경 이미지와 마찬가지로 아이콘도 날씨에 따라 변화하도록 함수를 만들었다.
OpenWeather API에서 제공하는 아이콘이 맘에 안들어서 Skycon을 사용하였다.
Skycon의 사용 방법은 아래 깃허브에 잘 나와있다.
나는 npm으로 설치하고 사용하였다.
https://github.com/bartosz121/react-skycons-extended
//SetSkyIcon.js
import { ReactSkycon } from 'react-skycons-extended';
export default function SetSkyIcon(id) {
let iconId = id === 800 ? 0 : (parseInt(id) / 100).toFixed(0);
switch (iconId) {
case 0:
return <ReactSkycon icon="CLEAR_DAY" size={30} />;
case '2':
return <ReactSkycon icon="THUNDER" size={30} />;
case '3':
return <ReactSkycon icon="SLEET" size={30} />;
case '5':
return <ReactSkycon icon="RAIN" size={30} />;
case '6':
return <ReactSkycon icon="SNOW" size={30} />;
case '7':
return <ReactSkycon icon="FOG" size={30} />;
case '8':
return <ReactSkycon icon="CLOUDY" size={30} />;
default:
return <ReactSkycon icon="CLEAR_NIGHT" size={30} />;
}
}
이렇게 배너가 완성되었고 아래 위치한 시간별 날씨를 보여주는 부분을 소개할 것이다.
시간별 날씨는 현재시간으로부터 3시간 간격으로 날씨를 보여준다.
< 시간별 날씨 >
//API Call
api.openweathermap.org/data/2.5/forecast?q={city name}&appid={API key}
//SeoulWeek.js
const [weather, setWeather] = useState('');
const url = `https://api.openweathermap.org/data/2.5/forecast?q=Seoul&appid=개인APIkey`;
// 날씨 가져오기
useEffect(() => {
axios
.get(url)
.then(responseData => {
const data = responseData.data;
setWeather({
dt0: data.list[3].dt_txt.substring(0, 13),
dt1: data.list[4].dt_txt.substring(0, 13),
dt2: data.list[5].dt_txt.substring(0, 13),
dt3: data.list[6].dt_txt.substring(0, 13),
dt4: data.list[7].dt_txt.substring(0, 13),
temp0: data.list[3].main.temp,
temp1: data.list[4].main.temp,
temp2: data.list[5].main.temp,
temp3: data.list[6].main.temp,
temp4: data.list[7].main.temp,
id0: data.list[3].weather[0].id,
id1: data.list[4].weather[0].id,
id2: data.list[5].weather[0].id,
id3: data.list[6].weather[0].id,
id4: data.list[7].weather[0].id,
hu0: data.list[3].main.humidity,
hu1: data.list[4].main.humidity,
hu2: data.list[5].main.humidity,
hu3: data.list[6].main.humidity,
hu4: data.list[7].main.humidity,
});
})
.catch(error => {
if (error.response && error.response.status === 429) {
console.error('많은 요청으로 오류가 발생합니다. 잠시 기다려주세요.');
}
});
}, [url]);
< 도시 검색 >
1. 검색한 도시의 날씨 불러오기
//WeatherDetail.js
const API_KEY = '개인 API key';
const [location, setLocation] = useState('');
const [result, setResult] = useState({});
const [week, setWeek] = useState({});
const searchUrl = `https://api.openweathermap.org/data/2.5/weather?q=${location}&appid=${API_KEY}`;
const weekUrl = `https://api.openweathermap.org/data/2.5/forecast?q=${location}&appid=${API_KEY}`;
//검색한 도시 날씨 불러오기
const searchWeather = async e => {
if (e.key === 'Enter') {
axios.get(searchUrl).then(responseData => {
const data = responseData.data;
setResult({
id: data.weather[0].id,
name: data.name,
main: data.weather[0].main,
temperature: data.main.temp,
temp_max: data.main.temp_max,
temp_min: data.main.temp_min,
feels_like: data.main.feels_like,
humidity: data.main.humidity,
wind: data.wind.speed,
clouds: data.clouds.all,
sunrise: data.sys.sunrise,
sunset: data.sys.sunset,
loading: false,
});
});
}
};
//검색한 도시 시간별 날씨 불러오기
const searchWeek = async e => {
if (e.key === 'Enter') {
axios.get(weekUrl).then(response => {
const week = response.data;
setWeek({
dt0: week.list[3].dt_txt.substring(0, 13),
dt1: week.list[4].dt_txt.substring(0, 13),
dt2: week.list[5].dt_txt.substring(0, 13),
dt3: week.list[6].dt_txt.substring(0, 13),
dt4: week.list[7].dt_txt.substring(0, 13),
temp0: week.list[3].main.temp_max,
temp1: week.list[4].main.temp_max,
temp2: week.list[5].main.temp_max,
temp3: week.list[6].main.temp_max,
temp4: week.list[7].main.temp_max,
id0: week.list[3].weather[0].id,
id1: week.list[4].weather[0].id,
id2: week.list[5].weather[0].id,
id3: week.list[6].weather[0].id,
id4: week.list[7].weather[0].id,
hu0: week.list[3].main.humidity,
hu1: week.list[4].main.humidity,
hu2: week.list[5].main.humidity,
hu3: week.list[6].main.humidity,
hu4: week.list[7].main.humidity,
});
});
}
};
2. 검색
Enter를 눌렀을 때,
visible: true → false (서울 날씨 화면 출력 x)
searchVisible: false → true (검색한 도시 날씨 화면 출력 o)
다른 도시를 검색하기 위해 Enter를 누르면 반대로 변해 서울 날씨 화면이 출력되므로
if문을 통해 visible === true일 경우만 변하도록 설정하였다.
//WeatherDetail.js
const [visible, setVisible] = useState(true); //서울 날씨
const [searchVisible, setSearchVisible] = useState(false); //검색한 도시 날씨
//검색했을 때 화면 전환
const changeDisplay = async e => {
if (e.key === 'Enter' && visible === true) {
try {
setVisible(!visible);
setSearchVisible(!searchVisible);
} catch (err) {
alert(err);
}
}
};
//WeatherDetail.js
//검색 Input
<div>
<FontAwesomeIcon icon={faMagnifyingGlass} />{' '}
<Input
placeholder="도시를 영어로 입력하세요."
value={location}
onChange={e => setLocation(e.target.value)}
type="text"
onKeyDown={searchWeather}
onKeyPress={searchWeek}
onKeyUp={changeDisplay}
/>
</div>
3. 출력
//WeatherDetail.js
{visible && <SeoulWeather />}
{searchVisible && (...)}
리액트를 제대로 공부하지 않고 유튜브와 블로그를 참고하여 만들어서 코드가 지저분하다.
props를 이용하면 더 간단하게 코드를 짤 수 있을 것 같다.
'Web > Front-End' 카테고리의 다른 글
React.js 기초 #3 JSX (0) | 2023.11.04 |
---|---|
React.js 기초 #2 Create React App (0) | 2023.11.04 |
React.js 기초 #1 React를 사용하는 이유 (1) | 2023.11.04 |
리액트 Class vs Function style (0) | 2023.08.11 |
OAuth 2.0 기본 개념 (1) | 2023.08.07 |