날씨 어플리케이션 만들기

Figma 이용하여 UI 디자인하기

openweathermap API, 날씨 정보 data 받기 [무료 API]

Current weather data API
Current weather data

postman 사용하여 데이터 조회
Postman API Platform | Sign Up for Free

개발환경설정

$ npx create-react-app weather-app
$ npm i react-icons --save
//App.js

import WeatherApp from "./WeatherApp";
import WeatherProvider from "./WeatherProvider/WeatherProvider";

function App() {
    return (
        <WeatherProvider>
            <WeatherApp />
        </WeatherProvider>
    );
}

export default App;

날씨 조회 API 상태관리 [Context API]

react의 context API를 이용해서 postman으로 호출한 API들을 가지고 불러온 데이터를
context API로 전역상태관리 해주기

  • useState를 이용해서 API가 비정기적으로 데이터를 불러오니까 데이터가 로드되면 그 state를 업데이트해서 Provider에 전달하는 방식으로 구현
//WeatherProvider.jsx

import React, { createContext, useEffect, useState } from "react";

export const WeatherContext = createContext({});

function WeatherProvider({ children }) {
    const [weatherInfo, setWeatherInfo] = useState({});
    const getWeatherInfo = async () => {
        try {
            const currentWeatherInfoAPI =
                "https://api.openweathermap.org/data/2.5/weather?appid=key값입력하기&q=seoul&units=metric";
            const currentWeatherInfo = await fetch(currentWeatherInfoAPI);
            const {
                name,
                coord: { lat, lon },
                main: {
                    temp,
                    humidity,
                    pressure,
                    feels_like,
                    temp_min,
                    temp_max,
                },
                sys: { sunset, sunrise },
                weather: [{ main: weatherState }],
                wind: { speed, deg },
            } = await currentWeatherInfo.json();
            const hourlyWeatherInfoAPI = `https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&appid=key값입력하기&units=metric`;
            const hourlyWeatherInfo = await fetch(hourlyWeatherInfoAPI);
            const { hourly } = await hourlyWeatherInfo.json();
            setWeatherInfo({
                name,
                temp,
                humidity,
                pressure,
                weatherState,
                feels_like,
                speed,
                deg,
                hourly,
                sunset,
                sunrise,
                temp_min,
                temp_max,
            });
        } catch (error) {
            console.error(error);
        }
    };
    useEffect(() => {
        getWeatherInfo();
    }, []);

    return (
        <WeatherContext.Provider value={{ ...weatherInfo }}>
            {children}
        </WeatherContext.Provider>
    );
}

export default WeatherProvider;

날씨 앱 구조

상단과 하단을 나누기 위해 컴포넌트 2개를 만들어줬다.

  • 상단 : MainWeather
    • 도시이름, 현재날씨[아이콘], 현재 온도, 최저기온, 최고기온을 useContext를 이용해서 전역상태를 가져와서 만들어준다.
    • 오늘의 요일과 시간은 day.js 라이브러리를 이용해서 가져와 만들어준다.
    • 날씨 아이콘은 상단, 하단 공통으로 쓰이기 때문에 따로 컴포넌트를 만들어 관리했다.

날씨 아이콘 관리

//MainWeatherIcon

import React from "react";
import {
  WiDayCloudy,
  WiDayRain,
  WiDaySunny,
  WiDust,
  WiDaySprinkle,
  WiDayThunderstorm,
  WiDaySnow,
  WiNa,
} from "react-icons/wi";
function MainWeatherIcon({ weatherState, ...props }) {
  switch (weatherState) {
    case "Thunderstorm":
      return <WiDayThunderstorm {...props} />;
    case "Snow":
      return <WiDaySnow {...props} />;
    case "Clouds":
      return <WiDayCloudy {...props} />;
    case "Clear":
      return <WiDaySunny {...props} />;
    case "Haze":
      return <WiDust {...props} />;
    case "Mist":
      return <WiDust {...props} />;
    case "Smoke":
      return <WiDust {...props} />;
    case "Dust":
      return <WiDust {...props} />;
    case "Fog":
      return <WiDust {...props} />;
    case "Sand":
      return <WiDust {...props} />;
    case "Ash":
      return <WiDust {...props} />;
    case "Squall":
      return <WiDust {...props} />;
    case "Tornado":
      return <WiDust {...props} />;
    case "Rain":
      return <WiDayRain {...props} />;
    case "Drizzle":
      return <WiDaySprinkle {...props} />;
    default:
      return <WiNa {...props} />;
  }
}

export default MainWeatherIcon;

상단 날씨 부분 개발하기

//MainWeather

function MainWeather() {
    const { name, temp, weatherState, temp_min, temp_max } =
        useContext(WeatherContext);
    return (
        <div className="weather">
            <div className="city">{name?.toUpperCase()}</div>
            <div className="weather-icon">
                <MainWeatherIcon
                    weatherState={weatherState}
                    viewBox="0 0 30 30"
                />
            </div>
            <div className="detail-weather">
                <div>
                    <div>{parseFloat(temp).toFixed(1)}&deg;</div>
                    <div className="detail-item">
                        <span>
                            &#9663;{parseFloat(temp_min).toFixed(1)}&deg;
                        </span>
                        <span>
                            &#9653;{parseFloat(temp_max).toFixed(1)}&deg;
                        </span>
                    </div>
                </div>
            </div>
        </div>
    );
}

export default MainWeather;

상단 요일,시간 부분 개발하기

//MainWeather

function MainWeather() {
	.
	.
	return (
		.
		.
		<div className="today">
	    <div>{dayjs().format('dddd').toUpperCase()}</div>
      <div>{dayjs().format('H:mm A')}</div>
    </div>
	)
}
  • 하단 : SubWeather

일출, 풍속, 습도를 useContext 이용해서 전역상태 가져오기

const { sunrise, speed, humidity } = useContext(WeatherContext);

sunrise는 초 단위로 정보가 내려오는데 new객체를 이용해서 밀리세컨드로 변환

new Date(sunrise * 1000).toLocaleString("en-US", {
	hour: "numeric",
	minute: "numeric",
	hour12: true,
})

전체 구성

function SubWeather() {
    const { sunrise, speed, humidity } = useContext(WeatherContext);
    return (
        <div className="sub-weather">
            <div className="sub-weather-item">
                <BsSunrise
                    style={{
						.
      					.
                    }}
                />
                <p className="sub-weather-text">
                    <span>SUNRISE</span>
                    {new Date(sunrise * 1000).toLocaleString("en-US", {
                        hour: "numeric",
                        minute: "numeric",
                        hour12: false,
                    })}
                </p>
            </div>
            <div className="sub-weather-item">
                <BsWind
                    style={{
						.
                        .
                    }}
                />
                <p className="sub-weather-text">
                    <span>WIND</span>
                    {`${speed}m/s`}
                </p>
            </div>
            <div className="sub-weather-item">
                <WiHumidity
                    style={{
   						.
                        .
                    }}
                />
                <p className="sub-weather-text">
                    <span>HUMIDITY</span>
                    {`${humidity}%`}
                </p>
            </div>
        </div>
    );
}

export default SubWeather;

수정사항

패스트캠퍼스로 강의를 듣고 난 후 다시 앱 디자인을 하여 만들어봤는데
역시 아쉬움이 많이 남는다. 무료API 종류가 바뀌기도 해서 더욱 아쉽다.

도시 검색 기능과 날씨에 따라 배경이 자동으로 바뀌는 기능도 추가해서
새로 업데이트 해야겠다는 생각이 든다.

나중엔 Heroku를 이용해서 배포도 해봐야겠다.

profile
Frontend Developer / Amateur Designer

0개의 댓글