💡 들어가며
우리는 사용자의 현재 위치를 받아서 외부의 **날씨 API(OpenWeather 등)**에 전달한 뒤,
반환된 온도·기상 상태·예보 정보 등을 화면에 띄울 수 있다.
오늘은 날씨 API 연동을 통해 각 날씨 정보를 가져와 앱 내 띄워 보도록 한다.
🌍 1. 날씨 API란?
앱이나 웹에서 현재 날씨를 표시하려면 기상 정보를 얻어야 한다.
이때 대부분은 기상청 API 또는 글로벌 날씨 API를 사용해야 하는데
이때 가장 많이 사용하는 API는 OpenWeather API이다.
☁️ 2. OpenWeather API 종류 쉽게 이해하기
| API 종류 | 설명 | |
| Current Weather API | 지금 이 순간의 날씨 | 무료 |
| 5-Day / 3-Hour Forecast | 5일 동안 3시간 간격 예보 | 무료 |
| Air Pollution API | 미세먼지(PM 2.5/PM 10) | 무료 |
| One Call API 3.0 | 현재 + 시간별 + 일별 + 미세먼지 묶인 패키지 | 유료 |
입문자는 Current Weather API 또는 5-Day Forecast API를 사용하는 것이 가장 쉽다.
🔑 3. OpenWeather API 키 발급받기
- https://openweathermap.org 방문
- 회원가입
- 로그인 후 API Keys 메뉴 이동
- 자동 생성된 API 키 복사

이 키를 API 요청 URL에 포함해야 정상적으로 데이터를 받을 수 있다.
예:
📍 4. 내 위치(위도/경도) 가져오기: Expo Location
React Native 기본만으로는 GPS 기능을 사용할 수 없다.
Expo 환경에서는 expo-location이라는 패키지를 이용하면 간단히 위치 정보를 얻을 수 있다.
설치
npx expo install expo-location
사용 방법
import * as Location from "expo-location";
const { granted } = await Location.requestForegroundPermissionsAsync();
if (!granted) return;
const {
coords: { latitude, longitude } // { 위도, 경도}
} = await Location.getCurrentPositionAsync();
이 코드가 돌아가면 내 스마트폰의 현재 GPS 좌표를 얻을 수 있다.
🌦️ 5. 날씨 API 요청 보내기 (fetch)
위도/경도를 얻으면 API 요청 URL에 넣어서 날씨 데이터를 요청한다.
현재 날씨(Current Weather) URL 예시:
const url = `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric`;
요청 및 JSON 파싱:
const response = await fetch(url);
const json = await response.json();
console.log(json);
반환 데이터 예시
{
"name": "Seoul",
"main": {
"temp": 18.5,
"feels_like": 18.0
},
"weather": [
{ "description": "clear sky", "icon": "01d" }
]
}
이제 json.main.temp 같은 값을 UI에 표시하면 된다.
📅 6. 5일 예보를 받아 화면에 보여주기
나는 5-Day Forecast API를 사용했기 때문에 3시간 간격으로 40개의 데이터가 온다.
list: [
{ dt_txt: "2025-11-18 06:00:00", main: {...}, weather: [...] },
{ dt_txt: "2025-11-18 09:00:00", main: {...}, weather: [...] },
...
]
따라서 위 구조를 날짜별로 묶어 다음처럼 변환했다:
2025-11-18 → 평균 온도, 대표 날씨
2025-11-19 → 평균 온도, 대표 날씨
...
날짜별 그룹화 개념:
const grouped = {};
json.list.forEach(item => {
const date = item.dt_txt.split(" ")[0];
if (!grouped[date]) grouped[date] = [];
grouped[date].push(item);
});
이렇게 그룹화된 데이터를 state로 저장하면 된다.
📲 7. 화면에 날씨 정보 렌더링하기
단일 날씨(현재 날씨)
<Text>{Math.round(temp)}°</Text>
<Text>{description}</Text>
5일 예보 → 가로 스크롤 UI
<ScrollView horizontal pagingEnabled>
{days.map((day, index) => (
<View key={index}>
<Text>{Math.round(day.temp)}°</Text>
<Text>{day.description}</Text>
<Text>{day.date}</Text>
</View>
))}
</ScrollView>
핵심 포인트
- horizontal -> 각 날씨 카드들을 가로로 리스트화
- pagingEnabled → 날씨 카드가 한 페이지씩 넘어감

🧩 8. 전체 흐름 요약
| 단계 | 설명 |
| 위치 권한 요청 | 스마트폰 GPS 사용 허용 받기 |
| 위도·경도 확인 | Location API로 좌표 획득 |
| 날씨 API 요청 | OpenWeather 호출하여 JSON 획득 |
| 데이터 가공 | 필요한 값만 추출 |
| UI 렌더링 | ScrollView, Text 컴포넌트로 표시 |
이 다섯 단계만 이해하면 어떤 날씨 앱도 구현할 수 있다.
☆첨부한 이미지 풀코드☆
export default function App() {
const [city, setCity] = useState("Loading...");
const [days, setDays] = useState([]);
const [ok, setOk] = useState(true);
const getWeather = async () => {
console.log("권한 체크 중…");
// 1) 위치 권한 요청
const { granted } = await Location.requestForegroundPermissionsAsync();
console.log("granted:", granted);
if (!granted) {
setOk(false);
return;
}
// 2) 현재 위치
const {
coords: { latitude, longitude }
} = await Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.High,
});
console.log("위치:", latitude, longitude);
// 3) reverse geocode → city
const geo = await Location.reverseGeocodeAsync(
{ latitude, longitude },
{ useGoogleMaps: false }
);
setCity(geo[0].city);
// 4) 5일 예보
const url = `https://api.openweathermap.org/data/2.5/forecast?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric`;
const response = await fetch(url);
const json = await response.json();
// 5) 날짜별 그룹화
const grouped = {};
json.list.forEach(item => {
const date = item.dt_txt.split(" ")[0];
if (!grouped[date]) {
grouped[date] = [];
}
grouped[date].push(item);
});
// 날짜별 평균 temp & 대표 description 생성
const result = Object.keys(grouped).map(date => {
const entries = grouped[date];
const avgTemp =
entries.reduce((sum, entry) => sum + entry.main.temp, 0) /
entries.length;
const descriptions = entries.map(e => e.weather[0].description);
const modeDescription = descriptions.sort(
(a, b) =>
descriptions.filter(v => v === a).length -
descriptions.filter(v => v === b).length
).pop();
console.log(modeDescription);
return {
date,
temp: avgTemp,
description: modeDescription,
};
});
setDays(result);
};
useEffect(() => {
getWeather();
}, []);
return (
<View style={styles.container}>
<View style={styles.city}>
<Text style={styles.cityName}>{city}</Text>
</View>
<ScrollView
pagingEnabled
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.weather}
>
{days.length === 0 ? (
<View style={styles.day}>
<ActivityIndicator color="black" size="large" style={{ marginTop: 100 }} />
</View>
) : (
days.map((item, index) => (
<View style={styles.day} key={index}>
<View style={{ flexDirection: "row", alignItems: "center"}}>
<Text style={styles.temp}>{Math.round(item.temp)}°</Text>
<Fontisto name={icons[item.description]} size={24} color="black" />
</View>
<Text style={styles.description}>{item.description}</Text>
<Text style={styles.date}>{item.date}</Text>
</View>
))
)}
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: "white" },
city: { flex: 1, justifyContent: "center", alignItems: "center" },
cityName: { fontSize: 68, fontWeight: "500" },
weather: { backgroundColor: "white" },
day: { width: SCREEN_WIDTH, alignItems: "center" },
temp: { marginTop: 50, fontSize: 80 },
description: { marginTop: -10, fontSize: 30, textTransform: "capitalize" },
date: { marginTop: 10, fontSize: 20, color: "gray" }
});
🔗 참고 자료
- OpenWeather 공식 문서
https://openweathermap.org/api - expo-location 공식 문서
https://docs.expo.dev/versions/latest/sdk/location/ - React Native ScrollView
https://reactnative.dev/docs/scrollview