반응형
이전 포스트에 이어서 날씨 정보 API를 사용하여 현재 위치 날씨를 보여주는 앱 페이지를 만들어 보겠습니다.
날씨 정보는 OpenWeatherMap을 사용합니다. 기본적인 사용법 및 API key 생성은 제 이전 포스트를 참고하기 바랍니다.
2023.12.13 - [개발활용툴] - 날씨 API - OpenWeather 사용하기(1)
1. 기본 기능 리스트
- 처음 앱 구동시 위치정보 동의 여부 확인하기
- 현재 핸드폰 위치정보 조회 하기
- 조회한 경위도 위치정보로 Openweathermap API 로 현재 위치 날씨 조회하기
2. 화면 UI 구성
- 지역명 - 시군구 표출
- 현재 시간 - 연월일 및 시각
- 현재 온도 - 단위 ℃
- 날씨 Icon - 날씨 정보에 매칭된 아이콘 표출
- 날씨 설명
3. 기능 구현
- 날씨 Icon
- expo/vector-icons 의 Fontisto 사용
- icons 에서 openweathermap에서 조회된 날씨에 해당하는 icon name를 지정
- 날씨 표출 명칭
- weather_name에서 openweathermap에서 조회된 날씨에 해당하는 한글 표출 명칭 지정
- 핸드폰 화면 크기 설정
- Dimensions 이용 화면의 폭(width)을 가져옴
- API_KEY
- openweathermap의 API 조회 key로 간단한 화면 구현을 위해 별도 환경변수로 빼지 않고 직접 App.js 파일내 작성
- 초기에 현재 위치 정보 불러오는데 시간 소요를 고려하여 city의 useState에 초기값으로 "Loading..." 이 표시되도록 함
- getWeather 함수에 필요한 기능 정의
- 위치정보 조회 승인 여부 확인
- accuracy 5 수준으로 현재위치 조회하여 조회된 값중 경위도(longitude, latitude) 값을 저장
- 경위도 값으로 주소지 가져와 city 값을 설정
- 경위도 값으로 현위치 날씨정보 조회하기
- Date 함수 이용하여 현재 시간 정보 가져오기
- useEffect 이용하여 앱 초기 구동시 getWeather가 한번만 실행되도록 함
- Activity Indicator 이용 초기 날씨 정보 없을 때 Loading indicator가 보이도록 함
size와 color로 크기와 색상값을 조절하여 표출 가능
import React, { useEffect, useState } from "react";
import * as Location from "expo-location";
import {
ScrollView,
StyleSheet,
Text,
View,
Dimensions,
ActivityIndicator,
} from "react-native";
import Fontisto from "@expo/vector-icons/Fontisto";
const SCREEN_WIDTH = Dimensions.get("window").width;
const API_KEY = "f47e5f61ac1c885d01fb7*********";
const icons = {
Clear: "day-sunny",
Clouds: "cloudy",
Atomsphere: "cloudy-gusts",
Snow: "snow",
Rain: "rains",
Drizzle: "rain",
Thunderstorm: "lighting",
};
const weather_name = {
Clear: "맑음",
Clouds: "구름",
Atomsphere: "구름많음",
Snow: "눈",
Rain: "비",
Drizzle: "이슬비",
Thunderstorm: "폭풍우",
};
const koreaTimeDiff = 9 * 60 * 60 * 1000;
export default function App() {
const [city, setCity] = useState("Loading...");
const [days, setDays] = useState([]);
const [ok, setOk] = useState(true);
const getWeather = async () => {
const { granted } = await Location.requestForegroundPermissionsAsync();
if (!granted) {
setOk(false);
}
const {
coords: { longitude, latitude },
} = await Location.getCurrentPositionAsync({ accuracy: 5 });
const location = await Location.reverseGeocodeAsync(
{ latitude, longitude },
{ useGoogleMaps: false }
);
setCity(location[0].district);
console.log(location);
const response = await fetch(
`https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric`
);
const json = await response.json();
setDays(json);
console.log(json);
};
const date = new Date(days.dt * 1000).toLocaleString("en-US", {
timeZone: "Asia/Seoul",
});
console.log("date", date);
useEffect(() => {
getWeather();
}, []);
return (
<View style={styles.container}>
<View style={styles.city}>
<Text style={styles.cityName}>{city}</Text>
</View>
<View>
<Text>{date}</Text>
</View>
<ScrollView
pagingEnabled
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.weather}
>
{days.length === 0 ? (
<View style={{ ...styles.day, alignItems: "center" }}>
<ActivityIndicator
color="white"
style={{ marginTop: 10 }}
size="large"
/>
</View>
) : (
<View style={styles.day}>
<View
style={{
flexDirection: "row",
alignItems: "center",
width: "100%",
justifyContent: "space-between",
}}
>
<Text style={styles.temp}>
{parseFloat(days.main.temp).toFixed(1)}
</Text>
<Fontisto
style={{ marginRight: 20 }}
name={icons[days.weather[0].main]}
size={68}
color="white"
/>
</View>
<Text style={styles.description}>
{weather_name[days.weather[0].main]}
</Text>
<Text style={styles.tinyText}>{days.weather[0].description}</Text>
</View>
)}
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "tomato",
},
city: {
flex: 1.2,
justifyContent: "center",
alignItems: "center",
},
cityName: {
fontSize: 68,
fontWeight: "500",
color: "white",
},
weather: {},
day: {
width: SCREEN_WIDTH,
alignItems: "center",
},
temp: {
marginTop: 50,
marginHorizontal: 20,
fontSize: 138,
color: "white",
},
description: {
marginTop: -30,
marginLeft: -200,
fontSize: 60,
color: "white",
},
tinyText: {
marginLeft: -250,
fontSize: 20,
color: "white",
},
});
👉 위치조회 결과 (샘플)
[{"city": null, "country": "대한민국", "district": "양천구", "formattedAddress": "대한민국 서울특별시 양천구 남부순환로 1", "isoCountryCode": "KR", "name": "남부순환로 1", "postalCode": null, "region": "서울특별시", "street": null, "streetNumber": "83길 18", "subregion": null, "timezone": null}]
👉 날씨API 조회 결과 (샘플)
{"base": "stations", "clouds": {"all": 0}, "cod": 200, "coord": {"lat": 37.5354, "lon": 126.8523}, "dt": 1731219725, "id": 1948005, "main": {"feels_like": 19.19, "grnd_level": 1018, "humidity": 45, "pressure": 1021, "sea_level": 1021, "temp": 19.96, "temp_max": 20.87, "temp_min": 17.9}, "name": "Kwangmyŏng", "sys": {"country": "KR", "id": 8105, "sunrise": 1731190017, "sunset": 1731227174, "type": 1}, "timezone": 32400, "visibility": 10000, "weather": [{"description": "clear sky", "icon": "01d", "id": 800, "main": "Clear"}], "wind": {"deg": 320, "speed": 2.57}}
날씨정보로 습도, 기압, 최대/최저 온도, 일출시간, 일몰시간, 풍속 등 다양한 정보가 있으므로 화면 구성에 따라 다양한 정보 표출 가능
반응형
'리액트(React)' 카테고리의 다른 글
[React] 유용한 Prop-Types 활용하기 (4) | 2024.11.12 |
---|---|
React Native - 기본 Template Component 만들기(1) (1) | 2024.11.11 |
React Native - 위치기반 날씨앱 만들기(1) (2) | 2024.11.09 |
[React Native] 갤러리&앨범 이미지 가져오기 (3) | 2024.09.21 |
React- dayjs 활용 날짜가공하기 (0) | 2024.09.09 |