개발자를 향해...
[React Native로 날씨앱 만들기] #2.0 Displaying Temperature ~ 본문
[React Native로 날씨앱 만들기] #2.0 Displaying Temperature ~
eugeneHwang1124 2021. 2. 26. 17:47이 글은 노마드 코더 님의 [ React Native로 날씨앱 만들기 ] 를 수강하며 작성하였습니다.
React Native로 날씨앱 만들기 - 노마드 코더 Nomad Coders
React Native Fundamentals
nomadcoders.co
#2.0 Displaying Temperature
weather api 문서를 살펴보면 값을 섭씨와 화씨 모두로 가져올 수 있다. 우리는 섭씨를 사용하기 때문에 섭씨 정보를 가져와야한다.
api 주소 부분의 뒤에 아래와 같이 &units=metric을 추가하면 섭씨 정보를 출력할 수 있다.
const { data } = await axios.get(`http://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&APPID=${API_KEY}&units=metric`);
이렇게 가져온 정보 중에 온도temp 정보와 main 정보를 받아와야한다. 우선 온도temp정보만 가져와보자.
파일 하단에 Weather.js 파일을 생성하고 여기서 props를 쓸 것이기 때문에 prop-types를 설치한다.(yarn add prop-types / npm install prop-types)
<Weather.js>
import React from "react";
import { View, Text, StyleSheet } from "react-native";
import PropTypes from "prop-types";
export default function Weather({temp}){
return (
<View style={styles.container}>
<Text>{temp}</Text>
</View>
);
}
Weather.propTypes = {
temp: PropTypes.number.isRequired
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent:"center",
alignItems:"center"
}
})
<App.js>
import React from "react";
import { Alert } from "react-native";
import Loading from "./Loading";
import * as Location from "expo-location";
import axios from "axios";
import Weather from "./Weather";
const API_KEY="//키 값";
export default class extends React.Component {
state={
isLoading:true
}
getWeather = async (latitude, longitude) => {
const { data } = await axios.get(`http://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&APPID=${API_KEY}&units=metric`);
console.log(data);
this.setState({ isLoading: false, temp: data.main.temp });
};
getLocation = async () => {
try{
const response=await Location.requestPermissionsAsync();
const {coords:{latitude, longitude}}=await Location.getCurrentPositionAsync();
this.getWeather(latitude, longitude);
}catch(error){ //사용자가 권한을 주지 않았을 때
Alert.alert("Can't find you.", "So sad");
}
}
componentDidMount(){
this.getLocation();
}
render(){
const {isLoading, temp}=this.state;
return isLoading ?<Loading />:<Weather temp ={temp} />;
}
}
props로 자식 컴포넌트인 Weather에게 온도를 넘겨주면 온도 값을 받은 Weather이 숫자 형태로 출력하게 된다.
온도를 넘겨줄 때는 state에 변수를 추가하는 방식으로 넘겨준다.
#2.1 Getting the Condition Names
openweathermap.org/current#listopenweathermap.org/weather-conditions로 가보면 날씨 코드에 대한 리스트를 보여준다. 여기서 제공하는 아이콘을 사용해보자.
아이콘을 나타내야하는 Weather.js로 가서 작업을 해보자. 우선 propTypes에서 상태에 대한 데이터를 App.js에서 받아와야한다. 아래와 같이 props에 condition을 추가해준다.
Weather.propTypes = {
temp: PropTypes.number.isRequired,
condition : PropTypes.oneOf(["Thunderstorm",
"Drizzle",
"Rain",
"Snow",
"Atmosphere",
"Clear",
"Clouds",
"Haze",
"Mist",
"Dust"]).isRequired
};
App.js에서 값을 props로 받았을 때 잘 되는지 시험해보기 위해 Clear이라는 값을 넘겨주자.
this.setState({ isLoading: false, condition:"Clear", temp: data.main.temp });
App.js의 setState에 condition을 추가해주고 하단에서 Weather에 인자로 넣어준다.
render(){
const {isLoading, temp, condition}=this.state;
return isLoading ?<Loading />:<Weather temp ={temp} condition ={condition} />;
}
이제 object를 다시 살펴보면 날씨 상태 정보는 weather > object 안에 배열형태로 저장되어있다. 따라서 다음과 같이 값을 가져온다.
getWeather = async (latitude, longitude) => {
const {
data:{
main :{
temp},
weather
}
} = await axios.get(`http://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&APPID=${API_KEY}&units=metric`);
console.log(data);
this.setState({ isLoading: false, condition:weather[0].main, temp: data.main.temp });
};
#2.2 Icons and Styling
<App.js>
import React from "react";
import { Alert } from "react-native";
import Loading from "./Loading";
import * as Location from "expo-location";
import axios from "axios";
import Weather from "./Weather";
import * as config from "./config";
export default class extends React.Component {
state={
isLoading:true
}
getWeather = async (latitude, longitude) => {
const {
data:{
main :{
temp},
weather
}
} = await axios.get(`http://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&APPID=${config.API_KEY}&units=metric`);
console.log(weather);
this.setState({
isLoading: false,
condition: weather[0].main,
temp
});
};
getLocation = async () => {
try {
await Location.requestPermissionsAsync();
const {
coords: { latitude, longitude }
} = await Location.getCurrentPositionAsync();
this.getWeather(latitude, longitude);
} catch (error) {
Alert.alert("Can't find you.", "So sad");
}
};
componentDidMount() {
this.getLocation();
}
render() {
const { isLoading, temp, condition } = this.state;
return isLoading ? (
<Loading />
) : (
<Weather temp={Math.round(temp)} condition={condition} />
);
}
}
이제 날씨 아이콘을 날씨 상태 값에 맞게 가져와보자.
여기서는 expo가 기본적으로 가지고 있는 icon들을 사용할 것이다. 아래와 같이 선언하면 가져와서 쓸 수 있다.
import { Ionicons } from '@expo/vector-icons';
icons.expo.fyi/여기서 원하는 아이콘을 볼 수 있다.
import { MaterialCommunityIcons } from '@expo/vector-icons';에서 모든 날씨 아이콘을 가져오기로 정하고 코드를 작성하면
<MaterialCommunityIcons name="weather-lightning-rainy" size={24} color="black" />
실행시켜보면 사이즈가 너무 작다. 따라서 크기를 키워주자. 그리고 상태를 설명하는 텍스트가 뜨는 view와 아이콘과 숫자 부분이 뜨는 view가 1:1이므로 flex를 1로 설정해준다. 그리고 상단의 상태바 아래로 화면이 뜨도록 설정해주자.
import React from "react";
import { View, Text, StyleSheet } from "react-native";
import PropTypes from "prop-types";
import { MaterialCommunityIcons } from '@expo/vector-icons';
export default function Weather({temp}){
return (
<View style={styles.container}>
<View style={styles.icon}>
<MaterialCommunityIcons size={86} name="weather-lightning-rainy" color="white" />
<Text style={styles.temp}>{temp}</Text>
</View>
<View style={styles.texts}></View>
</View>
);
}
Weather.propTypes = {
temp: PropTypes.number.isRequired,
condition : PropTypes.oneOf(["Thunderstorm",
"Drizzle",
"Rain",
"Snow",
"Atmosphere",
"Clear",
"Clouds",
"Haze",
"Mist",
"Dust"]).isRequired
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent:"center",
alignItems:"center",
paddingTop: Platform.OS === `ios` ? 0 : Expo.Constants.statusBarHeight,
backgroundColor:"#FDF6AA"
},
icon:{
flex:1,
justifyContent:"center",
alignItems:"center"
},
texts:{
flex:1,
justifyContent:"center",
alignItems:"center"
},
temp:{
fontSize:32,
color: "#FFFFFF",
}
})
실행결과는 다음과 같다.