[React] useEffect로 외부 async await(비동기) 함수 호출하기

김진평·2023년 1월 20일
0

React

목록 보기
1/3
post-thumbnail

현재 내 위치 기준으로 날씨를 알 수 있는 사이드 프로젝트를 진행하던 중이었다.

App Component에서 날씨 API를 호출하는게 아닌

별도의 js파일에서 내 위치 구하기 및 해당 위치의 날씨 API를 호출하여

내게 필요한 형태의 데이터로 가공 후 return하도록 비동기 함수를 작성하였다.

해당 함수를 App Component에서 호출하여 사용하도록 할 목적이다. (App.js는 가급적 clean하게 사용하기 위함..!)

이를 수행하기 위해 먼저 아래와 같이 순서를 나누었다.

  1. 내 위치의 위도 경도 구하기
  2. 구한 위도, 경도를 가지고 날씨 API를 호출해 원하는 데이터 가공하기

1. 내 현재 위치 위도 경도 구하기

먼저 GetCurrentWeather.js에서 위도, 경도를 구하는 처리를 진행했다.

GetCurrentWeather.js

export const GetCurrentWeather = async () => {
  const myPos = await getMyPos();
  const latitude = myPos.coords.latitude;
  const longitude = myPos.coords.longitude;
}


const getMyPos = () => {
  return new Promise((resolve, rejected) => {
    navigator.geolocation.getCurrentPosition(resolve, rejected);
  });
};

GetMyPos라는 함수는 navigator 객체를 사용하며
navigator.geolocation은 사용자의 현재 위치 정보를 가져오는 자바스크립트 API이다.

GetCurrentWeather()는 async 함수이기 때문에 정상적인 비동기 함수가 되려면
getMyPos()는 Promise 객체를 리턴해야 한다.

(※ 참고 : getCurrentPosition(success, error, option) -> 3개의 매개변수를 받으며 error, option은 생략 가능)
리턴된 myPos.coords를 통해 위도, 경도를 구할 수 있다.

2. 위도, 경도를 통해 날씨 API 호출하기

날씨 API를 사용하기 위해 weatherstack이라는 페이지에 가입해 APIKey를 발급받았다.
보안상 .env파일에 API URL, API Key 등을 환경변수로 설정하고
실제 통신할 때 process.env.{환경변수}로 접근해 API 호출을 진행했다.

GetCurrentWeather.js

export const GetCurrentWeather = async () => {
  const myPos = await getMyPos();
  const latitude = myPos.coords.latitude;
  const longitude = myPos.coords.longitude;

  return await getWeatherByCurrentLocation(latitude, longitude);
};

const getMyPos = () => {
  return new Promise((resolve, rejected) => {
    navigator.geolocation.getCurrentPosition(resolve, rejected);
  });
};

const getWeatherByCurrentLocation = async (lat, lon) => {
  let weather = {};
  const url = `${process.env.REACT_APP_WEATHER_URL}/current`;
  const apiKey = `${process.env.REACT_APP_WEATHER_API_KEY}`;

  try {
    const response = await fetch(
      `${url}?access_key=${apiKey}&query=${lat},${lon}`
    );
    const data = await response.json();
    if (data.success !== undefined && data.success === false) {
      throw new Error(data.error.info);
    }

    weather.country = data.location.country; //국가
    weather.city = data.location.name; //도시
    weather.temperature = data.current.temperature; //온도
    weather.whatherIcon = data.current.weather_icons; //날씨아이콘
    weather.weatherDescription = data.current.weather_descriptions; //날씨상태
    weather.windSpeed = data.current.wind_speed; //풍속
    weather.windDir = data.current.wind_dir; //풍향
    //return weather;
    return weather;
  } catch (error) {
    return error;
  }
};

전송 method는 get방식이며 fetch를 통해 통신을 진행한 후
리턴된 데이터를 가공하여 현재 내가 위치한 국가, 도시, 온도 등등 필요한 데이터를 가공하였다.

App.js

import { useEffect, useState } from "react";
import GlobalStyle from "./assets/styles/GlobalStyle";
import { GetCurrentWeather } from "./components/GetCurrentWeather";

function App() {
  const [data, setData] = useState();
  useEffect(() => {
    GetCurrentWeather().then((res) => setData(res));
  }, []);

  return (
    <>
      <GlobalStyle />
      {JSON.stringify(data)}
    </>
  );
}

export default App;

마지막으로 App.js에서 애플리케이션 시작시
GetCurrentWeather() 함수를 1회 호출해 사용하기 위해 useState, useEffect를 사용하였다.

useEffect 내에서 매개변수로 받는 함수는 async 함수가 아니므로
GetCurrentWeather 함수를 그냥 호출하게 되면 Promise 객체가 리턴되기 때문에
Promise[Pending] 상태가 되어버린다.

이런 경우에 .then을 이용해 Promise 객체의 리턴 값을 사용할 수 있다.

0개의 댓글