개발자를 향해...

[React Native로 날씨앱 만들기] #2.0 Displaying Temperature ~ 본문

웹 자바스크립트 공부/ReactJS + node.js

[React Native로 날씨앱 만들기] #2.0 Displaying Temperature ~

eugeneHwang1124 2021. 2. 26. 17:47
728x90
반응형

이 글은 노마드 코더 님의 [ 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",
    }
})

 

실행결과는 다음과 같다.

반응형