kok202
React native 강의 정리 (3)

2019. 8. 25. 00:53[공부] 영상/React native

날씨를 알려주는 어플을 만들 것인데, 크게 2개의 기능이 필요하다.

1. 현재 gps 정보를 읽을 수 있어야한다. -> GeoFencing 을 이용한다.

2. 현재 날씨를 알 수 있어야한다. -> 전세계 날씨를 알려주는 웹 서버의 API 를 활용할 것이다.

 

 

 

GeoFencing을 이용할 것인데, 특이한점은 GeoFencing 은 React native 에서는 제공하지 않는 컴포넌트라는 것이다. React native 에서는 GeoLocation 이라는 것으로 gps 정보를 제공하는데, GeoLocation 은 기능이 몇개 없다. GeoFencing 은 Expo 에서 제공하는 location component 중 하나이다. 만약 사용자가 특정 지역을 이탈하거나 다른 지역에 들어갔을 때 어떻게 하라는 명령을 내릴 수 있게된다.

GeoFencing 을 사용하기  위해선 expo-location 이 추가로 설치가 필요하다.

expo install expo-location

 

 

 

배경화면에 그라데이션 효과를 주고싶다. 그라데이션 효과를 넣을 수 있게 도와주는 컴포넌트가 이미 expo 에 만들어져있다. 이를 가져다가 쓰기만하면된다. 컴포넌트가 이렇게 하나로 뭉쳐있지않고 여러개로 분할 되어있는 이유는 expo 모듈 자체의 크기를 경량화 하고 불필요한 컴포넌트까지 설치할 때 같이 설치 되지 않도록 하기 위해서이다. 필요한 expo 컴포넌트는 알아서 찾아서 설치하고 써야한다. 설치하면 <LinearGradient> 컴포넌트를 사용할 수 있게된다.

expo install expo-linear-gradient

 

 

 

날씨 API 호출을 하기위해 클라이언트가 필요하다. 해당 강좌에서는 Axios 를 사용한다.

npm install axios --save

 

 

 

React prop type 을 지정할 수 있게 해주고 유효성도 검사해주는 기능을 설치하자.

npm install prop-types --save

 

 

 

App.js

import React, { Component } from "react";
import { StyleSheet, Text, View, StatusBar, Alert } from "react-native";
import axios from "axios";
import * as Location from "expo-location";
import Weather from "./Weather";
import Loading from "./Loading";

const API_KEY = "11111111111111111111111111111111";

export default class App extends Component {
  state = {
    isLoaded: false,
    temperatureFromWeb: null,
    weatherNameFromWeb: null
  };
  
  componentDidMount() {
    const position = this.getPosition();
    this.getWeather(position.coords.latitude, position.coords.longitude)
  }
  
  getPosition() => {
    try{
      await Location.requestPermissionsAsync();
      return await Location.getCurrentPositionAsync();
    }catch(){
      Alert.alert("Error!", "something went wrong!");
    }
  }
  
  getWeather(latitude, longitude) => {
    const {data} = await axios.get(
      `http://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&APPID=${API_KEY}`
    );
    this.setState({
      temperatureFromWeb: Math.floor(data.main.temp),
      weatherNameFromWeb: data.weather[0].main,
      isLoaded: true
    });
  }
  
  render() {
    return (
      <View style={styles.container}>
        <StatusBar hidden={true} />
        {this.state.isLoaded == false ? 
          <Loading/> :
          <Weather
              weatherName={this.state.weatherNameFromWeb}
              temperature={this.state.temperatureFromWeb}/>}
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff"
  }
});

Loading.js

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

export default class Loading extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.loadingText}>loading...</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "flex-end",
    paddingHorizontal: 30,
    paddingVertical: 100,
    backgroundColor: "#FDF6AA"
  },
  loadingText: {
    fontSize: 30,
    color: "#2c2c2c"
  }
});

Weather.js

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

const weatherCases = {
  Rain: {
    colors: ["#00C6FB", "#005BEA"],
    title: "Raining",
    subtitle: "subtitle when rainny",
    icon: "weather-rainy"
  },
  Clear: {
    colors: ["#FEF253", "#FF7300"],
    title: "Sunny",
    subtitle: "subtitle when clear",
    icon: "weather-sunny"
  },
  Snow: {
    colors: ["#7DE2FC", "#B9B6E5"],
    title: "Snow",
    subtitle: "subtitle when snow",
    icon: "weather-snowy"
  }
};

export default function Weather({ weatherName, temperature }) {
  return (
    <LinearGradient
      colors={weatherCases[weatherName].colors}
      style={styles.container}>
      <StatusBar barStyle="light-content"/>
      <View style={styles.upper}>
        <MaterialCommunityIcons
          size={96}
          color="white"
          name={weatherCases[weatherName].icon}/>
        <Text style={styles.temperature}>{temperature}</Text>
      </View>
      <View style={styles.lower}>
        <Text style={styles.title}>{weatherCases[weatherName].title}</Text>
        <Text style={styles.subtitle}>
          {weatherCases[weatherName].subtitle}
        </Text>
      </View>
    </LinearGradient>
  );
}

Weather.propTypes = {
  temperature: PropTypes.number.isRequired,
  weatherName: PropTypes.oneOf([
    "Rain",
    "Clear",
    "Snow"
  ]).isRequired
};

const styles = StyleSheet.create({
  container: {
    flex: 1
  },
  upper: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
    backgroundColor: "transparent"
  },
  temperature: {
    fontSize: 48,
    backgroundColor: "transparent",
    color: "white",
    marginTop: 10
  },
  lower: {
    flex: 1,
    alignItems: "flex-start",
    justifyContent: "flex-end",
    paddingLeft: 25,
    paddingRight: 25
  },
  title: {
    fontSize: 38,
    backgroundColor: "transparent",
    color: "white",
    marginBottom: 10,
    fontWeight: "300"
  },
  subtitle: {
    fontSize: 24
    backgroundColor: "transparent",
    color: "white",
    marginBottom: 100,
  }
});

강좌에서는 async function 을 만들고 함수 호출을 await 해주는 형식이였지만 생략한다.

 

'[공부] 영상 > React native' 카테고리의 다른 글

React native 강의 정리 (2)  (0) 2019.08.24
React native 강의 정리 (1)  (0) 2019.08.24