#2 Styles
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"]
},
Drizzle: {
iconName: "weather-hail",
gradient: ["#89F7FE", "#66A6FF"]
},
Rain: {
iconName: "weather-rainy",
gradient: ["#00C6FB", "#005BEA"]
},
Snow: {
iconName: "weather-snowy",
gradient: ["#7DE2FC", "#B9B6E5"]
},
Atmosphere: {
iconName: "weather-hail",
gradient: ["#89F7FE", "#66A6FF"]
},
Clear: {
iconName: "weather-sunny",
gradient: ["#FF7300", "#FEF253"]
},
Clouds: {
iconName: "weather-cloudy",
gradient: ["#D7D2CC", "#304352"]
},
Mist: {
iconName: "weather-hail",
gradient: ["#4DA0B0", "#D39D38"]
},
Dust: {
iconName: "weather-hail",
gradient: ["#4DA0B0", "#D39D38"]
},
Haze: {
iconName: "weather-hail",
gradient: ["#4DA0B0", "#D39D38"],
title: "Haze",
subtitle: "Just don't go outside."
}
};
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={96}
name={weatherOptions[condition].iconName}
color="white"
/>
<Text style={styles.temp}>{temp}°</Text>
</View>
<View style={styles.halfContainer} />
</LinearGradient>
);
}
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"
},
temp: {
fontSize: 42,
color: "white"
},
halfContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center"
}
});
#2.0 Displaying Temperature
1. getWeather 함수에 setState에 temp: data.main.temp 추가
이 때, data.main.temp는 axios에서 fetch한 api data의 temp 값이다. 해당 값을 state에 반영해준다.
2. 해당 temp 데이터를 Weather 컴포넌트 props값으로 넣어준다. 이때 소수값을 버리기 위해 반올림 처리 Math.round(값)을 props 값으로 전달해준다.
-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 = "32c05a076a33ba81efcbec86206960ec";
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`)
this.setState({ isLoading: false, temp: data.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 } = this.state;
return isLoading ? <Loading /> : <Weather temp={Math.round(temp)} />;
}
};
3. Weather 컴포넌트는 아래와 같이 구성 되어있다.
-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"
}
});
#2.1 Getting the Condition Names
1. api에 있는 condition 값을 가져 오자.
condition 값은 weather의 0번째 배열 값 안에 main 에 있다. 따라서 weather[0].main을 통해 가지고 올 수 있다. 해당값을 setState를 통해 state값으로 전달해주자. 그 값을 props로 Weather 컴포넌트에 전달해 준다.
-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 = "32c05a076a33ba81efcbec86206960ec";
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`
);
console.log(temp)
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} />
);
}
}
2. propTypes 부분에 condition 조건을 만들어 주었다. 아래 내용을 보면 된다.
-Weather.js
import React from "react";
import { View, Text, StyleSheet } from "react-native";
import PropTypes from "prop-types";
import { Ionicons } from "@expo/vector-icons";
export default function Weather({ temp }) {
return (
<View style={styles.container}>
<Text>{temp}</Text>
</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"
}
});
#2.2 Icons and Styling
expo 에서 제공해주는 아이콘들을 사용하기 위해서는 expo 공식 문서에 나와있는 모듈을 사용 하면 된다.
import { MaterialCommunityIcons(*모듈명) } from "@expo/vector-icons";
나머지 부분은 눈으로 읽어보면 이해된다.
MaterialCommunityIcons 태그 안에는 size, name 등의 정보가 필요하다. 여기서 name은 공식 문서에 있는 name을 써야함.
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.halfContainer}>
<MaterialCommunityIcons size={96} name="weather-lightning-rainy" />
<Text style={styles.temp}>{temp}o</Text>
</View>
<View style={styles.halfContainer} />
</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"
},
temp: {
fontSize: 42
},
halfContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center"
}
});
#2.3 Background Gradient
1. expo에서 제공하는 gradient를 사용해보자 (그라데이션 효과 , css가 아님). 먼저 npm install
expo-linear-gradient 명렁어 실행
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"]
},
Drizzle: {
iconName: "weather-hail",
gradient: ["#89F7FE", "#66A6FF"]
},
Rain: {
iconName: "weather-rainy",
gradient: ["#00C6FB", "#005BEA"]
},
Snow: {
iconName: "weather-snowy",
gradient: ["#7DE2FC", "#B9B6E5"]
},
Atmosphere: {
iconName: "weather-hail",
gradient: ["#89F7FE", "#66A6FF"]
},
Clear: {
iconName: "weather-sunny",
gradient: ["#FF7300", "#FEF253"]
},
Clouds: {
iconName: "weather-cloudy",
gradient: ["#D7D2CC", "#304352"]
},
Mist: {
iconName: "weather-hail",
gradient: ["#4DA0B0", "#D39D38"]
},
Dust: {
iconName: "weather-hail",
gradient: ["#4DA0B0", "#D39D38"]
},
Haze: {
iconName: "weather-hail",
gradient: ["#4DA0B0", "#D39D38"],
title: "Haze",
subtitle: "Just don't go outside."
}
};
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={96}
name={weatherOptions[condition].iconName}
color="white"
/>
<Text style={styles.temp}>{temp}°</Text>
</View>
<View style={styles.halfContainer}>
<Text style={styles.title}>Title</Text>
<Text style={styles.subtitle}>Subtitle</Text>
</View>
</LinearGradient>
);
}
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"
},
temp: {
fontSize: 42,
color: "white"
},
halfContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center"
},
title: {
color: "white",
fontSize: 40,
fontWeight: "300",
marginBottom: 10
},
subtitle: {
fontWeight: "600",
color: "white"
}
});