본문 바로가기
Developing Diary

[React 오답노트] Api 서비스를 이용하여 사용자에게 위치, 날씨정보 제공하기

by kurooru 2023. 1. 25.

< 목표 >
Weather API를 이용하여 사용자의 위치를 기반으로 도시와 현재 날씨를 제공한다.
* 먼저 파일 내에 axios, geolocation을 설치해 주어야 한다.
yarn add axios

yarn add react-navigator-geolocation

img.jsx -> Landing 화면을 분할하여 보여줄 코드
import { ImgContainorAboutus, ImgContainorConsulting, ImgContainorDefault, ImgContainorInterpretation, Title1, Title2, ShortSummary, LocationAndWeather } from "./style";
import getUserLocationAndWeather from "../../apis/locationAndWeather";
import { useEffect, useState } from "react";
import useGeolocation from "react-navigator-geolocation";
function Img ({currImg}) {
    
    const [data, setData] = useState();
    const { isEnabled, coords } = useGeolocation();
    useEffect(() => {
        async function fetchUserLocationAndWeatherData(isEnabled, coords) {
        const data = await getUserLocationAndWeather(isEnabled, coords);
        setData(data);
        }
        fetchUserLocationAndWeatherData(isEnabled, coords);
    }, [isEnabled, coords]);

    // default screen
    if (currImg === 'default') {

        return (
            <ImgContainorDefault>
                <Title1>
                    Hello,
                </Title1>
                <Title2>
                    We are HanIn Bridge !
                </Title2>
                <LocationAndWeather>
                    {data}
                </LocationAndWeather>
            </ImgContainorDefault>
            
        )
    }

    // screen to show when user hands over on button 'About us'
    else if (currImg === 'aboutus') {
        return (
            <ImgContainorAboutus>
                <ShortSummary>
                    HanIn Bridge,<br />
                    우리의 Partners,<br />
                    Director를 소개합니다
                </ShortSummary>
            </ImgContainorAboutus>
        )
    }

    // screen to show when user hands over on button 'Interpretation'
    else if (currImg === 'interpretation') {
        return (
            <ImgContainorInterpretation>
                <ShortSummary>
                    HanIn Bridge의<br />
                    핵심 서비스인<br />
                    번역 서비스를 소개합니다
                </ShortSummary>
            </ImgContainorInterpretation>
        )
    }

    // screen to show when user hands over on button 'Consulting'
    else if (currImg === 'consulting') {
        return (
            <ImgContainorConsulting>
                <ShortSummary>
                    함께, 인도네시아로<br />
                    HanIn Bridge의<br />
                    무역컨설팅을 소개합니다
                </ShortSummary>
            </ImgContainorConsulting>
        )
    }

}

export default Img;
LoctionAndWeather.js -> 위치와 날씨를 가져올 함수
import axios from "axios";

const getUserLocationAndWeather = async (isEnabled, coords) => {
    if (isEnabled) {
      // my own API key
      const API_KEY = "내 고유 API key (weather API에서 가져오시면 됩니다.)";
  
      // lat, lon
      const lat = coords.latitude;
      const lon = coords.longitude;
  
      // make url
      const url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}&units=metric`;
      
      // 비동기 처리
      const response = await axios.get(url); // check point

      try {
        const name = response.data.name;
        const weather = response.data.weather[0].main;
        const celsius = response.data.main.temp;
        return `${name} ${weather} ${celsius}℃`;
      } catch (error) {
        console.log(error);
      }
    }
    // before getting user's location
    else {
      return "loading…";
    }
};

export default getUserLocationAndWeather;
문제의 발생

리액트에서 어떻게 위치와 날씨를 가져오는지 몰랐다.

해결방안

먼저 api를 불러올 js 파일을 만들어준다. (LocationAndWeather.js)

여기서 axios를 사용해야 하는데, 여기서 비동기 처리라는 개념이 등장한다.

비동기 처리 방식이란, 원래 js파일은 파일 전체를 순차적으로 읽는 형태로 진행되는데,

API와 같이 시간이 걸리는 작업의 경우 여기에서 문제가 발생한다.

아직 데이터를 불러오지 못했는데, 다음 코드를 진행하려 하면 시간차가 발생하는 것이다.

따라서 await과 axios를 이용하여 이 코드가 끝나기 전까진 다음 코드를 읽지 마라 라는 메세지를 브라우저에 보내야 한다.

이 과정이 바로 const response = await axios.get(ulr)에 해당하는 것이다.

그러고 나서는 API서비스가 제공하는 정보를 받아 이를 반환해주는 함수를 만들어 사용하면 된다.

 

참고로 useGeolocation의 isEnabled와 coords는 객체의 키(key) 값이므로 이를 함부러 바꾸면 안된다.

해결코드
const [data, setData] = useState();
const { isEnabled, coords } = useGeolocation();
useEffect(() => {
    async function fetchUserLocationAndWeatherData(isEnabled, coords) {
    const data = await getUserLocationAndWeather(isEnabled, coords);
    setData(data);
    }
    fetchUserLocationAndWeatherData(isEnabled, coords);
}, [isEnabled, coords]);
import axios from "axios";

const getUserLocationAndWeather = async (isEnabled, coords) => {
    if (isEnabled) {
      // my own API key
      const API_KEY = "내 고유 API key (weather API에서 가져오시면 됩니다.)";
  
      // lat, lon
      const lat = coords.latitude;
      const lon = coords.longitude;
  
      // make url
      const url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}&units=metric`;
      
      // 비동기 처리
      const response = await axios.get(url); // check point

      try {
        const name = response.data.name;
        const weather = response.data.weather[0].main;
        const celsius = response.data.main.temp;
        return `${name} ${weather} ${celsius}℃`;
      } catch (error) {
        console.log(error);
      }
    }
    // before getting user's location
    else {
      return "loading…";
    }
};

export default getUserLocationAndWeather;