본 게시글에서는 우리나라 주변 바다의 위치의 좌표를 저장 후, weather API 로 날씨 정보를 읽어와 FlatList 로 표현한다.
* 공공데이터 포털 : https://www.data.go.kr/index.do
* 기상청 일일예보 : https://www.weather.go.kr/w/ocean/forecast/daily-forecast.do
1. 날씨를 확인할 위치 설정 및 Data.js 파일을 생성하여 좌표값 저장
* 기상청 지도에서 대략적인 해양 경계범위를 확인하고, 구글 지도에서 좌표를 가져옴
* 실제 프로젝트를 진행하면 DB를 별도로 구성하지만, react native 공부 목적으로 소스 내에 위치 정보를 저장함
# screens > WeatherData > Data.js
export const locationData = [
{
id: "1",
name: "동해북부",
latitude: "38.9912933625489",
longitude: "128.55904178990548",
},
{
id: "2",
name: "동해중부",
latitude: "38.11561234581255",
longitude: "129.37031290479666",
},
{
id: "3",
name: "동해남부",
latitude: "36.24956575214533",
longitude: "130.13587860476434",
},
{
id: "4",
name: "서해북부",
latitude: "38.6351611420487",
longitude: "124.23988007963995",
},
{
id: "5",
name: "서해중부",
latitude: "36.97413313314397",
longitude: "125.59961617361242",
},
{
id: "6",
name: "서해남부",
latitude: "35.248056938755774",
longitude: "125.62246888107414",
},
{
id: "7",
name: "남해서부",
latitude: "33.93118631207173",
longitude: "126.92507320639233",
},
{
id: "8",
name: "남해동부",
latitude: "34.516946052213186",
longitude: "129.06180135406336",
},
{
id: "9",
name: "제주도",
latitude: "32.862780223120836",
longitude: "126.42231364223444",
},
];
2. 저장한 위치 정보를 읽어와 FlatList 로 데이터 출력
* FlatList 참고 : https://reactnative.dev/docs/flatlist
* css 는 대략적으로 꾸며보았고, 실제 프로젝트 진행 시 UI/UX 담당자가 기획함
* ListItem 은 향후 Item 클릭 시 action 을 주기위해 TouchableOpacity 로 구성함
* 데이터 있을 때 : waiting -> rederItem 출력
* 데이터 없을 때 : waiting -> ListEmptyComponent 출력
# screens > WeatherData > index.js
import React, { useEffect, useState } from "react";
import { Text, View, Alert } from "react-native";
import styled from "styled-components";
//components
import Header from 'components/Header'
//API request
import axios from "axios";
//data
import { locationData } from "./Data"
const index = () => {
const [isLoading, setIsLoading] = useState(true);
const [currentWeather, setCurrentWeather] = useState('');
const [temp, setTemp] = useState('');
const [error, setError] = useState(false);
const API_KEY = "{개인별 발급한 key}";
const latitude = 38;
const longitude = 128;
useEffect(() => {
let mounted = true;
const getWeather = async (latitude, longitude) => {
try {
const resWeather = await axios.get(
`http://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric`
);
if (mounted) {
let _main = resWeather.data.weather[0].main;
let _temp = resWeather.data.main.temp;
setCurrentWeather(_main);
setTemp(_temp);
setIsLoading(false);
}
} catch (error) {
Alert.alert("날씨 정보를 읽어올 수 없습니다.")
setError(true);
setIsLoading(false);
}
};
getWeather(latitude, longitude);
return () => {
mounted = false
}
}, []);
return (
<Wrapper>
<Header title='날씨' />
{isLoading || error
? <Text> Waiting.. </Text>
: <Text> 날씨 : {currentWeather} , 온도 : {temp} </Text>
}
<List
data={locationData}
renderItem={({ item }) => (
<ListItem>
<TitleView>
<Title>{item.name}</Title>
</TitleView>
<Contents>{item.latitude} {item.longitude}</Contents>
</ListItem>
)}
keyExtractor={item => item.id}
ListEmptyComponent={() => (
<EmptyView>
<Text> 날씨 데이터가 없습니다.</Text>
</EmptyView>
)}
/>
</Wrapper>
);
};
export default index;
const Wrapper = styled.View`
flex: 1;
flex-direction: column;
background-color: white;
`;
const List = styled.FlatList`
margin-horizontal: 10px;
margin-top: 10px;
`;
const ListItem = styled.TouchableOpacity`
background-color: #E1F5FE;
margin-bottom: 10px;
height: 100px;
borderRadius: 10px;
`
const TitleView = styled.View`
flex: 1;
align-items: center;
justify-content: center;
background-color: #00B0FF;
padding-horizontal: 10px;
padding-vertical: 5px;
`
const Title = styled.Text`
color: white;
font-size: 17px;
font-weight: bold;
`
const Contents = styled.Text`
flex: 3;
font-size: 15px;
padding-horizontal: 10px;
padding-vertical: 5px;
`
const EmptyView = styled.View`
align-items: center;
`
* 정상적으로 데이터 수신 및 FlatList 로 보여줌
* 데이터 정보를 지우고 테스트 시, 설정한 화면이 정상적으로 나옴
3. 위치별 좌표값으로 weather API 를 활용하여 각각 날씨 정보 가져오기
* const [data, setData] = useState(locationData ? locationData : []) 로 위치 정보 초기값 저장
* for () 을 통해 weather API 각각 호출 후, setData() 로 날씨 및 기온 정보 추가
# screens > WeatherData > index.js
import React, { useEffect, useState } from "react";
import { Text, View, Alert } from "react-native";
import styled from "styled-components";
//components
import Header from "components/Header";
//API request
import axios from "axios";
//data
import { locationData } from "./Data";
const index = () => {
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(false);
const [data, setData] = useState(locationData ? locationData : []);
const API_KEY = "{개인별 발급한 key}";
useEffect(() => {
let mounted = true;
const getWeather = async (data) => {
try {
for (let i = 0; i < locationData.length; i++) {
const resWeather = await axios.get(
`http://api.openweathermap.org/data/2.5/weather?lat=${data[i].latitude}&lon=${data[i].longitude}&appid=${API_KEY}&units=metric`
);
data[i].currentWeather = resWeather.data.weather[0].main;
data[i].temp = resWeather.data.main.temp;
}
if (mounted) {
setData(data);
setIsLoading(false);
}
} catch (error) {
Alert.alert("날씨 정보를 읽어올 수 없습니다.");
setIsLoading(false);
}
};
getWeather(data);
return () => {
mounted = false;
};
}, [data]);
return (
<Wrapper>
<Header title="날씨" />
{isLoading ? (
<Text> Waiting.. </Text>
) : (
<List
data={data}
renderItem={({ item }) => (
<ListItem>
<TitleView>
<Title>{item.name}</Title>
</TitleView>
<Contents>
{item.currentWeather} // {item.temp}
</Contents>
</ListItem>
)}
keyExtractor={(item) => item.id}
ListEmptyComponent={() => (
<EmptyView>
<Text> 데이터 없음 </Text>
</EmptyView>
)}
/>
)}
</Wrapper>
);
};
export default index;
const Wrapper = styled.View`
flex: 1;
flex-direction: column;
background-color: white;
`;
const List = styled.FlatList`
margin-horizontal: 10px;
margin-top: 10px;
`;
const ListItem = styled.TouchableOpacity`
background-color: #e1f5fe;
margin-bottom: 10px;
height: 100px;
border-radius: 10px;
`;
const TitleView = styled.View`
flex: 1;
align-items: center;
justify-content: center;
background-color: #00b0ff;
padding-horizontal: 10px;
padding-vertical: 5px;
`;
const Title = styled.Text`
color: white;
font-size: 17px;
font-weight: bold;
`;
const Contents = styled.Text`
flex: 3;
font-size: 15px;
padding-horizontal: 10px;
padding-vertical: 5px;
`;
const EmptyView = styled.View`
align-items: center;
`;
* 정상적으로 모든 데이터가 잘 수신됨
4. 날씨에 따른 icon 보여주기
* react native Image 참고 : https://reactnative.dev/docs/images
* weather API icon 참고 : https://openweathermap.org/weather-conditions
# screens > WeatherData > index.js
import React, { useEffect, useState } from "react";
import { Text, View, Alert } from "react-native";
import styled from "styled-components";
//components
import Header from "components/Header";
//API request
import axios from "axios";
//data
import { locationData } from "./Data";
const index = () => {
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(false);
const [data, setData] = useState(locationData ? locationData : []);
const API_KEY = "{개인별 발급한 key}";
useEffect(() => {
let mounted = true;
const getWeather = async (data) => {
try {
for (let i = 0; i < locationData.length; i++) {
const resWeather = await axios.get(
`http://api.openweathermap.org/data/2.5/weather?lat=${data[i].latitude}&lon=${data[i].longitude}&appid=${API_KEY}&units=metric`
);
data[i].currentWeather = resWeather.data.weather[0].main;
data[i].temp = resWeather.data.main.temp;
data[i].icon = resWeather.data.weather[0].icon;
}
if (mounted) {
setData(data);
setIsLoading(false);
}
} catch (error) {
Alert.alert("날씨 정보를 읽어올 수 없습니다.");
setIsLoading(false);
}
};
getWeather(data);
return () => {
mounted = false;
};
}, [data]);
return (
<Wrapper>
<Header title="날씨" />
{isLoading ? (
<Text> Waiting.. </Text>
) : (
<List
data={data}
renderItem={({ item }) => (
<ListItem>
<TitleView>
<Title>{item.name}</Title>
</TitleView>
<ContentsView>
<Icon
source={{
uri: `http://openweathermap.org/img/wn/${item.icon}@2x.png`,
}}
/>
<Contents>
{item.currentWeather} → {item.temp} ℃
</Contents>
</ContentsView>
</ListItem>
)}
keyExtractor={(item) => item.id}
ListEmptyComponent={() => (
<EmptyView>
<Text> 데이터 없음 </Text>
</EmptyView>
)}
/>
)}
</Wrapper>
);
};
export default index;
const Wrapper = styled.View`
flex: 1;
flex-direction: column;
background-color: white;
`;
const List = styled.FlatList`
margin-horizontal: 10px;
margin-top: 10px;
`;
const ListItem = styled.TouchableOpacity`
background-color: #e1f5fe;
margin-bottom: 10px;
height: 80px;
border-radius: 10px;
`;
const TitleView = styled.View`
flex: 1;
align-items: center;
justify-content: center;
background-color: #00b0ff;
padding-horizontal: 10px;
padding-vertical: 5px;
`;
const Title = styled.Text`
color: white;
font-size: 17px;
font-weight: bold;
`;
const ContentsView = styled.View`
flex: 2;
flex-direction: row;
align-items: center;
justify-content: center;
`;
const Contents = styled.Text`
font-size: 15px;
padding-horizontal: 10px;
padding-vertical: 5px;
`;
const Icon = styled.Image`
width: 60px;
height: 60px;
`;
const EmptyView = styled.View`
align-items: center;
`;
* icon 이 잘 표현됨
* 실제 프로젝트에서는 휴대폰 기종별로 화면 크기가 다르기 때문에, css 작업 시 배율을 계산하여 상대적인 크기로 반영되도록 수정해야 함
끝.
'React Native > React Native_study' 카테고리의 다른 글
[리액트 네이티브를 다루는 기술 #2] 2장 컴포넌트 (p.99 ~ 108) (1) | 2021.12.20 |
---|---|
[리액트 네이티브를 다루는 기술 #1] 2장 컴포넌트 (p. 70 ~ 98) (0) | 2021.12.20 |
[React Native] #8 Open API를 활용한 날씨 데이터 가져오기 (0) | 2021.06.16 |
[React Native] #7 Google Maps 를 활용한 화면 구성 (0) | 2021.06.15 |
[React Native] #6 이미지를 읽어와 홈 화면 구성 (0) | 2021.06.11 |