React Native/React Native_study

[React Native] 날씨앱 만들기

bocoder
728x90
반응형

개발에 대한 기본지식이 전혀 없는 상태에서,

React native 앱개발자가 되기 위해 공부하는 과정을 기록.

 

우선 노마드코더 니꼴라스의 강의를 무작정 따라하면서 날씨앱을 만들어 보았다.

https://nomadcoders.co/courses

 

# 최종 결과물

012345

# 개발시 참고한 사이트

 

*react-native

https://reactnative.dev/

*expo

https://docs.expo.io/

* Weather API

https://openweathermap.org/

* Location API by IP

https://ip-api.com/

* UI gradients

https://uigradients.com/

 

# 코딩한 파일 내용

 

1) 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 = "d4dd95c2a7d78b9f27cd68a4b18c44ad";

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=${API_KEY}&units=metric`
      );

    this.setState({
      isLoading: false, 
      condition: weather[0].main, 
      temp: temp
    }); 
  };

  getLocation = async () => {
    try {
      await Location.requestPermissionsAsync();
      const { coords: { latitude, longitude } } = await Location.getCurrentPositionAsync();

      this.getWeather(latitude, longitude)
      this.setState({ isLoading: false });
      // Send to API sand get weather

    } 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="Thunderstorm" />); // 변경필요: condtion={condition}
  }
}

 

2) Weather.js

import React from "react";
import {View, Text, StyleSheet, StatusBar} from "react-native";
import PropTypes from "prop-types";
import { LinearGradient } from "expo-linear-gradient";
import { MaterialCommunityIcons } from "@expo/vector-icons";

const weatherOptions = {
    "Thunderstorm": {
        iconName: "weather-lightning",
        gradient: ["#373B44", "#4286f4"],
        title:"Thunderstorm is in house",
        subtitle:"Actually, outside of the house"
    },
    "Drizzle": {
        iconName: "weather-hail",
        gradient: ["#89F7FE", "#66A6FF"],
        title:"Drizzle",
        subtitle:"rain..?"
    },
    "Rain": {
        iconName: "weather-rainy",
        gradient: ["#00C6FB", "005BEA"],
        title:"",
        subtitle:"Don't forget the unbrella"
    },
    "Snow": {
        iconName: "weather-snowy",
        gradient: ["#7DE2FC", "#B9B6E5"],
        title:"Cold as balls",
        subtitle:"Do you want to build a snowman?"
    },
    "Atmosphere": {
        iconName: "weather-hail",
        gradient: ["#89F7FE", "#66A6FF"],
        title:"Atmosphere",
        subtitle:"Good mood"
    },
    "Clear": {
        iconName: "weather-sunny",
        gradient: ["#FF7300", "#FEF253"],
        title:"Sunny",
        subtitle:"Be carefull"
    },
    "Clouds": {
        iconName: "weather-cloudy",
        gradient: ["#D7D2CC", "#304352"],
        title:"Cloudy",
        subtitle:"I'm sad"
    },
    "Dust": {
        iconName: "weather-hail",
        gradient: ["#4DA0B0", "#D39D38"],
        title:"Dusty",
        subtitle:"Thanks a lot China"
    },
    "Haze": {
        iconName: "weather-hail",
        gradient: ["#4DA0B0", "#D39D38"],
        title:"Haze",
        subtitle:"Just don't go outside"
    },
    "Mist": {
        iconName: "weather-hail",
        gradient: ["#4DA0B0", "#D39D38"],
        title:"Misty",
        subtitle:"Stay at home"
    }
};

export default function Weather ({ temp, condition }) {
    return (
        <LinearGradient
            colors={weatherOptions[condition].gradient}
            style={styles.container}
        >
            <StatusBar barStyle="light-content" />
            <View style={styles.halfContainer}>
                <MaterialCommunityIcons
                    size={76}
                    name={weatherOptions[condition].iconName} 
                    color="white" />
                <Text style={styles.temp}>
                    {temp}º
                </Text>
            </View>
            <View style={{...styles.halfContainer, ...styles.textContainer}}>  
                <Text style={styles.title}>{weatherOptions[condition].title}</Text>
                <Text style={styles.subtitle}>{weatherOptions[condition].subtitle}</Text>
            </View>
        </LinearGradient>
    );
}

Weather.propTypes = {
    temp: PropTypes.number.isRequired,
    condition: PropTypes.oneOf([
        "Thunderstorm",
        "Drizzle", 
        "Rain", 
        "Snow", 
        "Atmosphere", 
        "Clear", 
        "Clouds",
        "Dust",
        "Haze",
        "Mist"

    ]).isRequired
};

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: "center",
        alignItems: "center"
    },
    temp: {
        fontSize: 30,
        color: "white"
    },

    halfContainer: {
        flex: 1,
        justifyContent: "center",
        alignItems: "center"
    },

    title: {
        color: "white",       
        fontSize: 40,
        fontWeight: "300",
        marginBottom: 10

    },

    subtitle: {
        color: "white",
        fontSize: 20,
        fontWeight: "600"
    },

    textContainer: {
        paddingHorizontal: 20,
        alignItems: "flex-start"
    }
});

 

3) Loading.js

import React from "react";
import { StyleSheet, Text, View, StatusBar } from 'react-native';

export default function Loading(){
    return <View style={styles.container}>
        <StatusBar barStyle="dark-content" />
        <Text style={styles.text}>Getting the weather</Text>
    </View>
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: "flex-end",
        paddingHorizontal: 30,
        paddingVertical: 100,
        backgroundColor: "#FDFAA5"
    },

    text: {
        color: "#2c2c2c",
        fontSize: 30
    }

});

 

728x90
반응형