📁 프로젝트 회고

SeSAC 3차 프로젝트 사용 기술 - 날씨 위젯

hjinn0813 2024. 5. 11. 16:59
728x90

현재 SeSAC 교육과정 3차 팀 프로젝트의 마무리 단계여서 해당 프로젝트에서 사용했던 기술들을 정리해보았다. 아직 실력이 부족해서 내가 맞게 설명하고 있는건지는 모르겠지만, 내가 아는 선에서 최대한 쉽게 설명해보려고 한다.

※ 사용언어 - HTML, JS, React, SASS, Bootstrap 등

※ 3차 프로젝트 github repo - https://github.com/treasure-2u/batDream


날씨 위젯은 Open Weather Map API에서 키를 발급받고 데이터를 불러와서 출력하는 '컴포넌트 제작' 과정과 SASS 스타일링 기법으로 디자인하는 과정으로 나누어서 진행했다. 디자인 관련 부분은 scss 확장자를 사용했기 때문에 특별하게 소개할 내용이 없어서, 컴포넌트 제작과정만 소개해보겠다.🙂

컴포넌트 초기 설정

import { useEffect, useState } from 'react';
import '../../styles/weather/Weather.scss';

// 날씨 api key
const WEATHER_API = {
  key: process.env.REACT_APP_WEATHER_API_KEY,
  base: 'https://api.openweathermap.org/data/2.5/',
};
  • useEffect, useState를 사용하기 위해 import했다. useEffect는 아래에서 현재 위치를 받아오는 함수를 위해 사용될거고, useState는 API를 통해 받아온 데이터들을 정상적으로 출력하기 위해 사용될 예정이다.
  • 컴포넌트 제작이 완료되면 디자인을 하기 위해 scss 파일을 import했다.
  • API key는 외부에 노출되면 안 되는 값이라서 .env 파일에 저장하여 환경변수로 사용했다.

함수형 컴포넌트 작성 시작 - useState, useEffect 사용

export default function Weather() {
  const [place, setPlace] = useState('');
  const [icon, setIcon] = useState('');
  const [nowWeather, setNowWeather] = useState('');
  const [temp, setTemp] = useState(0);
  const [error, setError] = useState('');

  useEffect(() => {
    getCurrentLocation();
  }, []);
}
  • API로 받아온 데이터 중에 내가 출력하고 싶은 것들만 useState로 '현재 상태'와 '앞으로 변화될 상태'를 구조분해할당하여 변수에 저장하고, 초기값은 빈 문자열이나 0을 주었다.
  • useEffect의 스코프에는 현재 위치를 받아오는 함수를 입력하였고, 의존성 배열에 빈 배열을 넘겨주어 컴포넌트가 최초 마운트될 때에만 실행될 수 있도록 했다.

geolocation API로 현재 위치 가져오기

const getCurrentLocation = () => {
  navigator.geolocation.getCurrentPosition((position) => {
    let lat = position.coords.latitude;
    let lon = position.coords.longitude;
    getNowWeather(lat, lon);
  });
};
  • 사용자 동의 하에 위치 정보를 가져오려면, 웹 브라우저의 geolocation API를 사용해야 한다.
  • 해당 함수의 인자로 position을 넘겨주고, 위도와 경도를 변수에 담아서 불러온다.
  • 이렇게 가져온 위도, 경도는 현재 날씨를 가져올 getNowWeather() 함수에 인자로 보내준다.

※ 참고 https://developer.mozilla.org/ko/docs/Web/API/GeolocationPosition

 

GeolocationPosition - Web API | MDN

GeolocationPosition 인터페이스는 주어진 시간에 장치가 위치한 지점을 나타냅니다. 지점은 Coordinates 객체로 표현하여, 지구를 나타내는 회전타원체 위의 2D 위치와 더불어 높이와 속도 정보를 담습

developer.mozilla.org


JSON 데이터 불러와서 현재 날씨 확인하기

const getNowWeather = (lat, lon) => {
  let openmap = `https://api.openweathermap.org/data/2.5/weather`
  let url = `${openmap}?lat=${lat}&lon=${lon}&appid=${WEATHER_API.key}&units=metric&lang=kr`;
  
  fetch(url)
    .then((response) => response.json())
    .then((data) => {
      setPlace(data.name);
      setIcon(data.weather[0].icon);
      setNowWeather(data.weather[0].description);
      setTemp(Math.round(data.main.temp)); // 소수점 이하 제거
    })
    .catch((error) => setError('ERROR'));
};
  • 현재 날씨를 불러오는 함수에 인자로 방금 가져온 위도, 경도를 보내준다.
  • Open Weather Map API에서 데이터를 불러올 주소를 url이라는 변수에 저장한다.
    주소 끝의 'units=metric'은 온도를 섭씨로 표현하기 위해, 'lang=kr'는 날씨에 대한 설명을 한글로 출력하기 위해 사용했다.
  • fetch()를 이용해 JSON 데이터를 불러오고, useState의 setter 함수로 원하는 정보만 받아온다.
    setTemp의 경우에는 받아온 데이터에 소수점 이하 부분까지 있어서, 그 부분을 잘라내고 정수만 보여주려고 Math.round() 메서드를 사용했다.
  • 마지막으로 catch()를 통해, 오류를 잡아내면 'ERROR'라는 메시지를 띄우도록 설정했다.

위젯 클릭시 네이버 날씨로 연결하는 함수 설정

const goToNaverWeather = () => {
  let url = `https://weather.naver.com`;
  window.open(url, '_blank'); // 새 창에서 열기
};
  • 이동할 주소(네이버 날씨 페이지)를 url이라는 변수에 담았다.
  • 새로운 탭이나 창을 열어주는 window.open() 메서드의 첫번째 인자로 이동할 주소를 담고, 두번째 인자로 이동방법을 명시했다.

return문 작성하기

return (
  <div className="weather-main" onClick={goToNaverWeather}>
    <div className="weather-place">{place}</div>
    <div className="weather-info">
      {icon && (<img className="weather-icon" src={`https://openweathermap.org/img/w/${icon}.png`} alt="Weather-icon"/>)}
      &nbsp;
      <div className="weather">{nowWeather}</div>
    </div>
    <div className="temp-now">{temp}°C</div>
    {error && <div>Error: {error}</div>}
  </div>
);
  • 화면에 실제로 출력시키기 위해, 함수형 컴포넌트의 return문 내부에 내가 보여주고 싶은 데이터들을 작성했다. 해당 컴포넌트를 클릭하면 네이버 날씨로 이동해야하기 때문에, 최상위 태그에 onClick으로 미리 만들어놓은 goToNaverWeather() 함수를 연결했다.
  • 화면에는 현재 위치(장소)와 아이콘, 날씨에 대한 텍스트 설명, 현재 온도만 보여주도록 했다.
    날씨 아이콘의 경우에는 Open Weather Map API에서 제공하는 아이콘을 그대로 사용했다.
  • ERROR는 만약 존재하면 출력되고, 그렇지 않으면 생략되도록 && 연산자를 사용해 작성했다.

이렇게 컴포넌트를 만들고, src/pages/main.jsx에서 해당 컴포넌트를 불러와서 return에 입력하니 정상적으로 화면에 출력되었다. 날씨 위젯은 메인 페이지에서만 보여지는 요소여서, 다른 배너와 어울리도록 디자인을 약간 만지고 default 배경화면으로 구름 사진을 넣어서 완성시켰다.👏

완성된 날씨 위젯


💡 날씨 위젯 개발 과정에서의 문제와 해결방법

https://openweathermap.org/weather-conditions

Weather Conditions - OpenWeatherMap

We use cookies to personalize content and to analyze our traffic. Please decide if you are willing to accept cookies from our website.

openweathermap.org

사실 날씨 위젯은 Open Weather Map API에서 제공하는 'Weather condition codes'를 이용하여 날씨에 따라 위젯의 배경화면이 변경되도록 하고 싶었다. 그래서 함수형 컴포넌트 안에서 if문으로 조건 설정하고 Unsplash에서 찾아온 날씨 관련 사진들을 return에 경로로 입력했지만, 지정한 조건에 맞는 사진들이 제대로 나오지 않았다. 당시에 내 담당인 미세먼지 위젯은 전혀 진도가 안 나가고 있는 상황인데 개발 시간은 촉박해서, 결국 이런 기능을 포기하고 default 배경사진을 넣는 것으로 계획을 변경하여 제작했다. 2차 프로젝트부터 느낀거지만, 개발 과정에서는 빠른 판단력과 과감한 포기도 필요한 것 같다.🤔


여기까지가 날씨 위젯에 대한 기술 설명이었다.

React는 이번에 처음 배운거라 초반에 많이 헤맸는데 구글링과 chatGPT를 이용하여 혼자 해결하려고 노력했다. 날씨 API는 2차 프로젝트 당시에 사용했던 로그인 API와는 전혀 다른 느낌이었어서, 직접 코드를 작성해보며 많이 배웠다.

앞으로도 쑥쑥 커보자..!🌱

728x90