Language/Type Script

[Type Script] openweathermap API를 사용하여 도시 날씨 정보 보여주기 with React

나는김혜린 2022. 2. 9. 18:54

openweathermap이란?

: 무료로 세계 모든 도시의 현재 날씨 정보 API를 사용할 수 있는 착한 API이다.

현재 날씨 정보 이외에도 일일 예보, 푸시 알림 등 다른 여러 가지 API도 사용할 수 있다.

 

openweathermap을 사용해보자!

https://openweathermap.org/

 

Weather API - OpenWeatherMap

Please, sign up to use our fast and easy-to-work weather APIs for free. In case your requirements go beyond our freemium account conditions, you may check the entire list of our subscription plans. You can read the How to Start guide and enjoy using our po

openweathermap.org

먼저 이 웹사이트에 들어가 회원가입을 해준다!

이름, 이메일, 비밀번호만 작성하면 회원가입이 끝나기 때문에 매우 간편하다.

 

그 후 오른쪽 상단에 자신의 이름을 클릭하고 My API keys에 들어가준다.

위 사진에서 빨간색 동그라미가 자신의 API key이다.

나중에 사용해야하니 복사해두자

 

https://api.openweathermap.org/data/2.5/weather?q=도시이름&units=&lang=kr&appid=자신의APIkey

-> 이렇게 사용할 수 있다.

예를 들어 서울의 날씨 정보가 궁금하다면

https://api.openweathermap.org/data/2.5/weather?q=seoul&units=&lang=kr&appid=자신의APIkey

이 url을 주소창에 검색한다.

 

검색해보면 이런 형태의 데이터를 확인할 수 있다.

main의 temp는 현재 온도, coord의 lon과 lat는 위도, 경도를 말한다.

그 외의 데이터가 무엇을 의미하는지 알고 싶다면

https://openweathermap.org/current

 

Current weather data - OpenWeatherMap

Access current weather data for any location on Earth including over 200,000 cities! We collect and process weather data from different sources such as global and local weather models, satellites, radars and a vast network of weather stations. Data is avai

openweathermap.org

여기서 알 수 있다.

 

이제 API를 어떻게 사용할 수 있는지 알았으니 React, Typescript와 함께 이 API를 응용해 사용해보자!

 

React, Typescript로 날씨 정보 웹앱 만들기

npx create-react-app <앱이름> --template=typescript

-> typescript 기반의 react 프로젝트를 만들었다.

 

위 사진처럼 src 폴더 안에 interface라는 폴더를 만들어주고 App.tsx를 수정하자.

 

전체 코드

import React, {ChangeEvent, FormEvent, useEffect, useState} from 'react';
import { Weather } from './interfaces/wather';
import { Cloud } from './interfaces/cloud';

const App:React.FC = () => {
  const [city, setCity] = useState('seoul');
  const [weather, setWeather] = useState<Weather|null>(null);
  const [cloud, setCloud] = useState<Cloud|null>(null);
  // useState 훅은 타입 안정성을 위해 제네릭을 사용해야 함

  const getWeather = async(city:string) => {
    const response = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=&lang=kr&appid=APIKey`;
    fetch(response, {
      "method":"GET",
    })
    .then((res) => res.json())
    .then((data) => {
      console.log(data);
      if(data.cod === 200) {
      const cityTemp:Weather = data.main;
      cityTemp.city = data.name;
      const cityCloud:Cloud = data.weather[0];
      setWeather(cityTemp);
      setCloud(cityCloud);
    } else {
      setWeather(null);
      setCloud(null);
    }})
  }
  useEffect(() => {getWeather(city)}, []); // 빈 배열은 훅을 한 번만 호출한다는 의미이다

  const handleChange = (event:ChangeEvent<HTMLInputElement>) => {
    setCity(event.target.value); //상태를 업데이트
  }

  const handleSubmit = (event:FormEvent) => {
    console.log(`handleSubmit`)
    event.preventDefault(); 
    getWeather(city);
  };

  let ErrorMsg:string = '';
  if(weather === null && cloud === null) {
    ErrorMsg = `${city}의 날씨를 찾을 수 없습니다.`;
  } else {
    ErrorMsg = '';
  }

  return (
    <div>
      <form>
        <input type="text" placeholder='Enter City' onChange={handleChange}/>
        <button type='submit' onClick={handleSubmit}>Get weather</button>
        <h2>City:{city}</h2>
        {/* {weather && <h2>Temperature : {weather.temp}F</h2>} */}
      </form>
      {weather && <h2>Temp : {Math.floor(weather.temp - 273)}°</h2>}
      {cloud && <h2>Cloud : {cloud.description}</h2>}
      <h2>{ErrorMsg}</h2>
    </div>
  )

}

export default App;

 

먼저 검색한 도시, 온도, 구름의 데이터를 저장하기 위해 useState를 사용해 city(검색한 도시), weather(온도), cloud(구름) 변수를 만든다. 도시의 기본값은 seoul로 설정해 처음 웹을 실행했을 때 서울의 날씨 정보를 보이게 한다.

여기서 weather과 cloud는 제네릭 타입을 사용했는데, 아까 만든 interface 폴더 안에 각각의 제네릭 타입을 선언한 파일을 만든다.

그리고 각각 파일 안에 아래와 같이 interface를 선언하고 반환한다.

오른쪽 사진은 JSON 데이터이다.

이 두 인터페이스는 아까 보았던 데이터를 사용하기 위해 만든 틀이라고 생각하면 된다.

 

그리고 API를 가져와 JSON 형식의 데이터로 바꾸고 그 데이터를 콘솔로 출력 후 state를 바꾸는 함수를 작성한다.

const response = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=&lang=kr&appid=`;

먼저 response라는 상수에 url을 할당하는데, 아까 API를 사용한 것처럼 q= 뒤에 검색한 도시 즉, city 변수를 넣어준다.

이 response를 fetch를 사용해 JSON 형식의 데이터로 만들고 console창에 출력한다.

 

그리고 만약 데이터의 cod가 200이라면 (검색한 도시가 있다면이랑 같은 뜻) 아래 내용을 실행한다.

cityTemp(검색한 도시의 온도)는 데이터의 main 값인데, 아까 봤던 데이터에서 main은 city, feels_like, temp 등의 정보를 가진 것으로 볼 수 있다. 그래서 이 검색한 도시의 온도를 setWeather로 weather 변수의 값을 재할당해준다.

cityCloud 또한 같다. json 형식의 데이터를 다루는 방법은 서치하셈!!

 

그리고 만약 검색한 도시의 날씨 정보가 없거나 도시를 잘 못 입력했다면 weather, cloud 값을 null로 할당한다.

 

그 다음 useEffect를 사용해 렌더링 후 getWeather 함수를 실행하고, 빈 배열을 사용해 훅을 한 번만 호출한다.

 

위는 사용자가 input 태그에 입력할 때마다 city 변수의 값을 업데이트하는 함수이다.

 

사용자가 검색버튼을 눌렀을 때 실행되는 함수이다. 콘솔 출력은 굳이 안 해줘도 되고

preventDefault() 메서드로 태그의 기본적인 동작(form이므로 새로고침)을 제한하고

getWeather함수로 입력한(바뀐) city값을 넘기고 실행한다.

 

그리고 이 구문은 사용자가 잘못된 값을 입력했을 때 실행되는 예외처리이다.

 

input 태그에서 값이 변할 때마다(onChange) handleChange 함수를 실행시키고 버튼을 클릭하면 handleSubmit 함수를 실행한다.

현재 state의 city값을 보여주고, 온도, 구름 정보를 보여준다. 그리고 잘못 입력했다면 에러메세지를 출력한다.

 

온도값을 보여줄 때 API 자체에서 켈빈 온도로 주어 273을 빼주어 우리가 아는 섭씨 온도로 바꾸고 Math.floor 메서드를 사용해 소수점을 제거한다.

그리고 구름은 데이터에 한국어로 설명된 데이터가 있길래 그 데이터를 썼다.

 

이렇게 하면 완성! (css는 귀찬아서 안 넣었다.

 

완성본

 

담소

오랜만에 웹다운 웹을 만들어본 거 같아 더 집중이 잘 되고 재밌었당

API를 써본 거는 처음이라 흥미로웠고 책이 좀 예전꺼라 지금 사용법이랑 달라 구글링하며 찾았다.

그리고... 온도가 F라고 돼있길래 화씨온도인 줄 알고 다른 API를 찾아보고 했는데 알고보니 켈빈 온도였다...

책 나빠