NEXT_PUBLIC_ACCUWEATHER_KEY=*******************
'use client'
import { useEffect, useState } from "react";
interface Location {
latitude: number | null;
longitude: number | null;
}
export default function Home() {
const [location, setLocation] = useState<Location>({ latitude: null, longitude: null });
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const getCurrentLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
// 성공적으로 위치를 가져온 경우
const { latitude, longitude } = position.coords;
setLocation({ latitude, longitude });
},
(err) => {
// 위치 가져오기 실패 시 오류 메시지 저장
setError(err.message);
}
);
} else {
// Geolocation을 지원하지 않는 브라우저의 경우 오류 메시지 저장
setError("이 브라우저는 Geolocation을 지원하지 않습니다.");
}
};
getCurrentLocation();
}, []); // 컴포넌트가 처음 렌더링될 때 한 번만 실행
return (
<>
<div className="flex flex-col items-center justify-center w-full h-full">
{error ? (
<div className="text-red-500">오류: {error}</div>
) : (
<div>
<div className="font-bold">사용자의 현재 위치</div>
<div>{location.latitude} / {location.longitude}</div>
</div>
)}
</div>
</>
);
}
사용자가 브라우저에서 위치 권한을 허용하면
이렇게 현재 위치를 가져올 수 있다.
만약 위치 권한을 차단한다면 이렇게 오류 메시지가 나온다.
※ API를 받아오기 전에,
accuweather의 api는 CORS 에러를 발생시켰습니다.
필요하신 분은 임시로 아래 방법으로 CORS 에러를 우회하시기 바랍니다.
cors-anywhere
https://cors-anywhere.herokuapp.com
주소를 붙인다.interface Location {
key: number;
city: string;
localizedName: string;
}
export async function getLocation(lat: number, lng: number) {
const response = await fetch(
// CORS error를 임시로 우회
`https://cors-anywhere.herokuapp.com/http://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=${process.env.NEXT_PUBLIC_ACCUWEATHER_KEY}&q=${lat}%2C${lng}&language=ko-kr`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}
);
const result = await response.json();
if (result) {
const location: Location = {
key: result.ParentCity.Key, // 날씨 api에 사용할 지역 키
city: result.AdministrativeArea.LocalizedName, // 화면에 보여줄 지역 정보
localizedName: result.ParentCity.LocalizedName, // 화면에 보여줄 지역 정보
};
return location;
} else {
throw new Error(result);
}
}
쿼리 스트링 정보
응답 json 데이터
{
"Version": 1,
"Key": "3429991", // 도시의 고유 키
"Type": "City", // 데이터 타입
"Rank": 55, // 도시의 순위
"LocalizedName": "**동", // 지역의 한국어 이름 (마스킹 처리)
"EnglishName": "**-dong" // 지역의 영어 이름 (마스킹 처리)
"PrimaryPostalCode": "", // 우편번호 (nullable)
"Region": {
"ID": "ASI",
"LocalizedName": "아시아",
"EnglishName": "Asia"
},
"Country": {
"ID": "KR",
"LocalizedName": "대한민국",
"EnglishName": "South Korea"
},
"AdministrativeArea": {
"ID": "11",
"LocalizedName": "서울시",
"EnglishName": "Seoul",
"Level": 1,
"LocalizedType": "특별시",
"EnglishType": "Special City",
"CountryID": "KR"
},
"TimeZone": {
"Code": "KST",
"Name": "Asia/Seoul",
"GmtOffset": 9.0,
"IsDaylightSaving": false,
"NextOffsetChange": null
},
"GeoPosition": {
"Latitude": 37.***, // 위도 (마스킹 처리)
"Longitude": 126.***, // 경도 (마스킹 처리)
"Elevation": {
"Metric": {
"Value": 18.0, // 해발 고도 (미터)
"Unit": "m", // 단위 (미터)
"UnitType": 5 // 단위 유형
},
"Imperial": {
"Value": 59.0, // 해발 고도 (피트)
"Unit": "ft", // 단위 (피트)
"UnitType": 0 // 단위 유형
}
}
},
"IsAlias": false,
"ParentCity": {
"Key": "2330435",
"LocalizedName": "강서구",
"EnglishName": "Gangseo-gu"
},
"SupplementalAdminAreas": [
{
"Level": 2,
"LocalizedName": "강서구",
"EnglishName": "Gangseo-gu"
}
],
"DataSets": [
"AirQuality",
"AirQuality-Regional",
"AirQualityCurrentConditions",
"AirQualityForecasts",
"Alerts",
"DailyLocalIndices",
"ForecastConfidence",
"FutureRadar",
"HourlyLocalIndices",
"MinuteCast",
"PremiumAirQuality",
"Radar",
"TidalForecast"
]
}
'use client'
import { getLocation, getWeather } from "@/api/weatherApi";
import { useEffect, useState } from "react";
interface Location {
latitude: number | null;
longitude: number | null;
}
interface LocationData {
key: number;
city: string;
localizedName: string;
}
export default function Home() {
const [location, setLocation] = useState<Location>({ latitude: null, longitude: null });
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [locationData, setLocationData] = useState<LocationData>();
const [weatherData, setWeatherData] = useState<Weather>();
const fetchLocationData = async () => {
if (location.latitude !== null && location.longitude !== null) {
setLoading(true);
try {
const result = await getLocation(location.latitude, location.longitude);
setLocationData(result);
} catch (error) {
console.error("Error fetching location data:", error);
setError("위치 정보를 가져오는 중 오류가 발생했습니다.");
} finally {
setLoading(false);
}
}
};
useEffect(() => {
const getCurrentLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
// 성공적으로 위치를 가져온 경우
const { latitude, longitude } = position.coords;
setLocation({ latitude, longitude });
fetchLocationData();
},
(err) => {
// 위치 가져오기 실패 시 오류 메시지 저장
setError(err.message);
}
);
} else {
// Geolocation을 지원하지 않는 브라우저의 경우 오류 메시지 저장
setError("이 브라우저는 Geolocation을 지원하지 않습니다.");
}
};
getCurrentLocation();
}, []); // 컴포넌트가 처음 렌더링될 때 한 번만 실행
useEffect(() => {
if (location.latitude !== null && location.longitude !== null) {
fetchLocationData();
}
}, [location]);
return (
<>
{locationData && (
<div className="mt-4 text-center">
<div className="font-bold">위치 정보</div>
<div>도시: {locationData.city}</div>
<div>지역명: {locationData.localizedName}</div>
<div>위치 키: {locationData.key}</div>
</div>
)}
</>
);
}
interface Weather {
weatherText: string;
weatherIcon: number;
temperature: number;
}
export async function getWeather(key: number) {
const response = await fetch(
// CORS error를 임시로 우회
`https://cors-anywhere.herokuapp.com/http://dataservice.accuweather.com/currentconditions/v1/${key}?apikey=${process.env.NEXT_PUBLIC_ACCUWEATHER_KEY}&language=ko-kr`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}
);
const result = await response.json();
if (result) {
const weather: Weather = {
weatherText: result[0].WeatherText, // 날씨 상태
weatherIcon: result[0].WeatherIcon, // 날씨 아이콘 코드
temperature: result[0].Temperature.Metric.Value, // 기온 (섭씨)
};
return weather;
} else {
throw new Error(result);
}
}
[
{
"LocalObservationDateTime": "2024-11-01T09:41:00+09:00", // 관측 시간
"EpochTime": 1730421660,
"WeatherText": "흐림", // 날씨 상태
"WeatherIcon": 7, // 날씨 아이콘 코드
"HasPrecipitation": false, // 강수 여부
"PrecipitationType": null, // 강수 유형 (없으면 null)
"IsDayTime": true, // 낮 여부 (true: 낮, false: 밤)
"Temperature": {
"Metric": {
"Value": 14.5, // 섭씨 온도
"Unit": "C", // 단위 (섭씨)
"UnitType": 17 // 단위 유형
},
"Imperial": {
"Value": 58.0, // 화씨 온도
"Unit": "F", // 단위 (화씨)
"UnitType": 18 // 단위 유형
}
},
"MobileLink": "http://www.accuweather.com/ko/kr/gangseo-gu/2330435/current-weather/2330435",
"Link": "http://www.accuweather.com/ko/kr/gangseo-gu/2330435/current-weather/2330435"
}
]
'use client'
import { getLocation, getWeather } from "@/api/weatherApi";
import { useEffect, useState } from "react";
interface Location {
latitude: number | null;
longitude: number | null;
}
interface LocationData {
key: number;
city: string;
localizedName: string;
}
interface Weather {
weatherText: string;
weatherIcon: number;
temperature: number;
}
export default function Home() {
const [location, setLocation] = useState<Location>({ latitude: null, longitude: null });
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [locationData, setLocationData] = useState<LocationData>();
const [weatherData, setWeatherData] = useState<Weather>();
const fetchLocationData = async () => {
if (location.latitude !== null && location.longitude !== null) {
setLoading(true);
try {
const result = await getLocation(location.latitude, location.longitude);
setLocationData(result);
await fetchWeatherData(result.key);
} catch (error) {
console.error("Error fetching location data:", error);
setError("위치 정보를 가져오는 중 오류가 발생했습니다.");
} finally {
setLoading(false);
}
}
};
const fetchWeatherData = async (locationKey: number) => {
try {
const result = await getWeather(locationKey);
setWeatherData(result);
} catch (error) {
console.error("Error fetching weather data:", error);
setError("날씨 정보를 가져오는 중 오류가 발생했습니다.");
} finally {
setLoading(false);
}
};
useEffect(() => {
const getCurrentLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
// 성공적으로 위치를 가져온 경우
const { latitude, longitude } = position.coords;
setLocation({ latitude, longitude });
fetchLocationData();
},
(err) => {
// 위치 가져오기 실패 시 오류 메시지 저장
setError(err.message);
}
);
} else {
// Geolocation을 지원하지 않는 브라우저의 경우 오류 메시지 저장
setError("이 브라우저는 Geolocation을 지원하지 않습니다.");
}
};
getCurrentLocation();
}, []); // 컴포넌트가 처음 렌더링될 때 한 번만 실행
useEffect(() => {
if (location.latitude !== null && location.longitude !== null) {
fetchLocationData();
}
}, [location]);
return (
<>
<div className="flex flex-col items-center justify-center w-full h-full">
{error && <div>Error: {error}</div>}
{loading ? (
<div className="flex items-center">
Loading...
</div>
) : (
locationData && weatherData && (
<div className="flex items-center w-full justify-center">
<img src={`/assets/weather/${weatherData.weatherIcon}-s.png`} alt="Weather Icon" className="w-1/3 h-auto" />
<div className="text-left">
<div className="text-3xl font-bold">{weatherData.temperature} °C</div>
<div className="font-bold">{weatherData.weatherText}</div>
<div className="text-slate-500">{locationData.city} {locationData.localizedName}</div>
</div>
</div>
)
)}
</div>
</>
);
}
References