귀여운 눈높이에서 작성된, 🐰

하루 한 걸음씩, 성장 하는 중 입니다 🫶🏻

Studying/미니 프로젝트

개인 프로젝트 - 날씨 앱 (2) 현재 위치의 날씨 받아오기 (메인페이지구성)

creamymood 2025. 5. 27. 13:58
 

개인 프로젝트 - 날씨 앱 (1) 현재 위치 받아오기

날씨앱 메인페이지에서 구현 할 내용이, 내가 있는 위치의 날씨 정보 이므로, 현재 위치를 우선 알아야 한다.그 과정에 필요한 내용.날씨 앱 말고도 현재 위치로써 활용할 수 있을 내용이 많을

creamymood.tistory.com

 

앞 게시글에서 이어집니다.


2. 현재 위치 날씨 호출 하기

 

현재 위치를 받아왔으니, 해당 정보를 기반으로 날씨도 호출해보자.

큰 틀은 다음과 같다.

 

1. Home.jsx에서 현재 날씨를 호출한다. 

2. 받아온 정보에서 필요한 내용들로 아래 내용 처럼 간단한 필요한 구성을 한다.


 

같이 공부하시는 동기님이 알려주신 날씨 API 사이트


❶ 우선 회원가입을 한 뒤, key 값을 받고, .env 변수에 담아, 컴포넌트에선 import 해둔다.

 

const key = import.meta.env.VITE_WEATHER_KEY

 

 

❷ 현재 날씨를 호출 하는 법은 간단하다.

https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={API key}

 

날씨 호출 해오는 코드의 lat은 위도 / lon은 경도다.

 

* 참고로 다국어 지원도 한다. 엔드포인트는 다음을 참고하자.

더보기

한국이면 lang에 kr 넣으면 됨~

&lang=kr

 

이렇게 적으면, 

이렇게 뜨는데, 도시는.. 변경이 안되나보다.

이 부분 동기님이 언급해주셨는데, 한번 고민해봐야겠다.

 

컴포넌트 분리 전에,

우선 메인 페이지인, home.jsx에서 위치를 불러 왔었다.

 //현재 위치 받아오기 함수
    useEffect(()=>{
        navigator.geolocation.getCurrentPosition(
        
            function success(position){
                setLat(position.coords.latitude)
                setLon(position.coords.longitude)},
            function error(error){console.log(error)}
            )
       
    },[])

해당 코드 처럼 latitude와 longtitude를 각각 상태로써 저장해줬다.

 

이 값으로

const [lat, setLat] = useState(null)
    const [lon, setLon] = useState(null)
    const [weather, setWeather] = useState(null)
    // const key = import.meta.env.VITE_WEATHER_KEY

    const fetchWeather = async (lat, lon) => {
        const key = import.meta.env.VITE_WEATHER_KEY
        const url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${key}`

        try{
        const respose =  await fetch(url);
        const data =  await respose.json()
        console.log(data)
        setWeather(data)

        }catch (error){
            console.error('날씨 데이터를 불러오지 못했습니다:', error);
        }
    }

날씨를 호출하는 함수를 만든다. 

데이터를 받아온 뒤, 그것 역시 날씨 데이터로 저장해준다.

 

그 뒤, fetchWeather 함수를 실행하는데, lat과 lon 값이 있을 때! fetchWeather을 실행하도록,

아래처럼 useEffect안에 넣어준다.

useEffect(() => {
        if (lat && lon) {
            fetchWeather(lat, lon);

        }
    }, [lat, lon]);

 

그리고 콘솔을 확인해보면,

이렇게 잘 뜨는 것을 확인 할 수 있다.

 

공식 문서에서 API 응답에 대한 부분을 설명해주고 있는데, 아래 데이터 정보를 확인 후 

필요한 데이터를 추출하여 화면에 렌더링 해주면 된다.

더보기
                          
{
   "coord": {
      "lon": 7.367,
      "lat": 45.133
   },
   "weather": [
      {
         "id": 501,
         "main": "Rain",
         "description": "moderate rain",
         "icon": "10d"
      }
   ],
   "base": "stations",
   "main": {
      "temp": 284.2,
      "feels_like": 282.93,
      "temp_min": 283.06,
      "temp_max": 286.82,
      "pressure": 1021,
      "humidity": 60,
      "sea_level": 1021,
      "grnd_level": 910
   },
   "visibility": 10000,
   "wind": {
      "speed": 4.09,
      "deg": 121,
      "gust": 3.47
   },
   "rain": {
      "1h": 2.73
   },
   "clouds": {
      "all": 83
   },
   "dt": 1726660758,
   "sys": {
      "type": 1,
      "id": 6736,
      "country": "IT",
      "sunrise": 1726636384,
      "sunset": 1726680975
   },
   "timezone": 7200,
   "id": 3165523,
   "name": "Province of Turin",
   "cod": 200
}

 

설명:

  • coord
    • coord.lon위치의 경도
    • coord.lat위치의 위도
  • weather(자세한 정보 날씨 상황 코드 )
    • weather.id날씨 상태 ID
    • weather.main날씨 매개변수 그룹(비, 눈, 구름 ​​등)
    • weather.description그룹 내 날씨 상황입니다. 자세한 내용은 여기에서 확인하세요. 원하는 언어로 결과를 확인하실 수 있습니다. 자세히 알아보기
    • weather.icon날씨 아이콘 ID
  • base내부 매개변수
  • main
    • main.temp온도. 기본 단위: 켈빈, 미터법: 섭씨, 영국식: 화씨
    • main.feels_like온도. 이 온도 매개변수는 사람의 날씨 인식을 반영합니다. 단위 기본값: 켈빈, 미터법: 섭씨, 영국식: 화씨
    • main.pressure해수면의 대기압, hPa
    • main.humidity습도, %
    • main.temp_min현재 최저 기온입니다. 현재 관측된 최저 기온입니다(대도시 및 도시 지역). 자세한 내용은 여기에서 확인하세요. 기본 단위: 켈빈, 미터법: 섭씨, 영국식: 화씨
    • main.temp_max현재 최고 기온입니다. 현재 관측된 최고 기온입니다(대도시 및 도시 지역). 자세한 내용은 여기에서 확인하세요. 기본 단위: 켈빈, 미터법: 섭씨, 영국식: 화씨
    • main.sea_level해수면의 대기압, hPa
    • main.grnd_level지상의 대기압, hPa
  • visibility시정, 미터. 시정의 최대값은 10km입니다.
  • wind
    • wind.speed풍속. 기본 단위: 미터/초, 미터법: 미터/초, 영국식 단위: 마일/시
    • wind.deg풍향, 도(기상학적)
    • wind.gust돌풍. 단위 기본값: 미터/초, 미터법: 미터/초, 영국식: 마일/시
  • clouds
    • clouds.all흐림, %
  • rain
    • 1h(사용 가능한 경우) 강수량(mm/h). 이 매개변수의 측정 단위는 mm/h만 사용 가능합니다.
  • snow
    • 1h(사용 가능한 경우) 강수량(mm/h). 이 매개변수의 측정 단위는 mm/h만 사용 가능합니다.
  • dt데이터 계산 시간, 유닉스, UTC
  • sys
    • sys.type내부 매개변수
    • sys.id내부 매개변수
    • sys.message내부 매개변수
    • sys.country국가 코드(GB, JP 등)
    • sys.sunrise일출 시간, 유닉스, UTC
    • sys.sunset일몰 시간, 유닉스, UTC
  • timezoneUTC에서 초 단위 변화
  • id 도시 ID. 내장된 지오코더 기능은 더 이상 지원되지 않습니다. 자세한 내용은 여기를 참조하세요.
  • name 도시 이름입니다. 기본 제공 지오코더 기능은 더 이상 지원되지 않습니다. 자세한 내용은 여기를 참조하세요.
  • cod내부 매개변수

 

❸ 그리고 필요한 데이터로 이제 return 부분을 채워준다.

 

 

주의 !

1) weather는 비동기로 받아오는 데이터기 때문에

(처음 렌더링 시점에 weather 값이 아직 null. 즉, weather.name이나 weather.weather[0]에 접근하려 할 때 에러가 발생할 수 있다.)

따라서, 조건부 렌더링으로써 weather가 존재하고 weather.weather가 배열인지 확인한 다음에 렌더링하도록 !

 

2) 받아온 데이터에 ICON도 있는데, 이걸 실제 이미지로 변경 하고 싶을 땐, 아래를 참고해보자

더보기

 날씨 아이콘을 텍스트로 보여주는 게 아니라 진짜 이미지로 보여주고 싶을 때는, OpenWeatherMap에서 제공하는 아이콘 URL 포맷을 사용하면 된다.


 1. 아이콘 코드란?

weather.weather[0].icon 이 부분에는 "01d", "03n" 같은 코드가 들어 있어.
이 코드는 날씨 아이콘을 식별하는 문자열이야.

weather.weather[0].icon // "01d"

 

 2. 이미지로 변환하는 방법

아이콘 이미지는 다음 형식의 URL을 쓰면 돼:

http://openweathermap.org/img/wn/{icon}@2x.png

여기서 {icon} 자리에 코드 (01d 등)가 들어가.

 

예:

<img src={`http://openweathermap.org/img/wn/${weather.weather[0].icon}@2x.png`} alt="weather icon" />

3. 현재 위치 날씨 칸을 누르면 디테일 페이지로 이동하기

 

우선 이렇게 현재 위치를 기반으로 날씨까지 받아와서, 해당 정보로 화면을 꾸려주었다.

 

(2) 현재 위치 칸을 누르면, 디테일로 가기 위한 구성을 하기 위해 router를 설치해주었고 다음과 같이 페이지 설정을 해주었다.

 

css 스타일링을 하기 전에, 우선 div 칸을 누르면 디테일로 이동하게끔 구현 하고 싶은데

 

내 머릿속에서 생각한 방법은, LINK를 div 안에 넣을 수 있나 ?

 

<div> 자체를 클릭해서 이동하게 하고 싶다면, <Link>를 <div>처럼 꾸미거나, <div> 대신 <Link>를 쓰는 게 더 좋다.

 

 

 1) div 안에 Link 넣는 건 괜찮음:

<div>
  <Link to="/home">Home</Link>
</div>

2 ) div를 클릭해서 이동하게 하고 싶을 때 이렇게 하면 접근성/SEO에 안 좋음:

<div onClick={() => navigate('/home')}>Home</div>

 

이유?  ↓

더보기

"접근성(Accessibility)이나 SEO(Search Engine Optimization)에 안 좋다"는 건 웹사이트를 사용하는 사용자나 검색 엔진에게 불리하게 작용할 수 있다는 뜻

 예시 코드 (접근성/SEO에 안 좋음)

<div onClick={() => navigate('/home')}>
  홈으로 가기
</div>

왜 이게 안 좋을까?

1. 접근성 문제 (Accessibility)

  • 스크린 리더(시각장애인용 보조 도구) 는 <a>, <button> 같은 HTML 기본 태그를 기준으로 동작한다.
  • <div>는 기본적으로 클릭 가능한 요소로 인식되지 않아, 키보드로 접근이 불가능하거나, 어떤 동작이 있는지 인식하기 어렵다.
  • 키보드로만 웹을 사용하는 사람은 이걸 "클릭할 수 있는 버튼"이나 "링크"라고 느끼지 못한다.

2. SEO 문제 (Search Engine Optimization)

  • 검색 엔진은 <a href="..."> 같은 명확한 링크 구조를 통해 페이지 간 관계를 이해한다.
  • <div>에 onClick을 써서 페이지 이동하게 하면 검색 엔진이 링크로 인식하지 못해서 페이지 연결 정보를 놓쳐, SEO 점수에 불리하게 작용할 수 있다.

 

올바른 방법

방법 1: <Link>를 사용

import { Link } from 'react-router-dom';

<Link to="/home" className="my-div-style">
  홈으로 가기
</Link>

CSS로 스타일을 줘서 <div>처럼 보이게 만들 수 있음.

 

방법 2: <button> + navigate (버튼 역할일 때)

import { useNavigate } from 'react-router-dom';

function MyComponent() {
  const navigate = useNavigate();

  return (
    <button onClick={() => navigate('/home')}>
      홈으로 가기
    </button>
  );
}

 

이럴 땐 <Link> 자체를 스타일링:

<Link to="/home" style={{ display: 'block', padding: '1rem', background: '#eee' }}>
  Home
</Link>

 

 

 

 

그럼 우선 이렇게 되었고, 클릭 시 detail로 이동까지 된다.


추가 +

UI 목표에서 온도를 보여줘야 하는데, 기본적으로 API 호출에서 받아오는 데이터 값은 kelvin이므로 (1) 변환을 해주던가, (2) 처음부터 섭씨로 API를 호출 해와야 한다.

다행히, OpenWeather 사이트에서 섭씨로써 호출 해오는 엔드포인트를 제공한다.

https://api.openweathermap.org/data/2.5/weather?lat=57&lon=-2.15&appid={API key}&units=metric

이렇게 호출 하면 됌! 전체적으로 코드를 수정해줄 필요가 있다.


다음 게시글에선 도시 기반으로 날씨를 보여주는 (7)~(9) 기능을 구현 해보겠다. 🤍💘


참고한 블로그 :

 

 

[React] API로 날씨 앱 만들기 1(OpenWeather API 사용)

오늘은 API를 사용하여 날씨 앱을 만들어 보자. 최종 결과물은 아래와 비슷한 구성이 될 것이다. https://velog.io/@gyultang/React%EB%A1%9C-%EB%82%A0%EC%94%A8%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0OpenWeather-API React로 날씨

conquer-it.tistory.com