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 |