오늘은 어제 테스트했던 현재 위치, 날씨를 작업 중인 프로젝트에 이식했다.
1) 현재 위치
현재 위치가 적용되어야 할 부분은 업로드, 내주변, 궁금해요 총 세 곳이다.
먼저 어제와 마찬가지로 hook을 만들었다.
import { useEffect, useState } from "react";
import axios from "axios";
import { useDispatch } from "react-redux";
import { getLocation } from "../store/modules/acountSlice";
const useLocationHook = () => {
const dispatch = useDispatch()
const [address, setAddress] = useState('');
const [location, setLocation] = useState({
latitude: 0,
longitude: 0,
nowLocationCity: '',
nowLocationGu: '',
error: null,
});
const loading = {
latitude: 0,
longitude: 0,
nowLocationCity: '현재위치',
nowLocationGu: '조회중',
error: null,
}
useEffect(() => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(success, error);
} else {
setLocation({
...location,
error: '현재위치 기능을 지원하지 않는 브라우저입니다.',
});
}
}, []);
const success = (position) => {
const { latitude, longitude } = position.coords;
getKakaoAddress(latitude, longitude);
};
const error = (err) => {
setLocation({
...location,
error: '현재위치를 가져올 수 없습니다.',
});
};
const getKakaoAddress = async (latitude, longitude) => {
const kakaoApiKey = 'apikey';
try {
const response = await axios.get(`https://dapi.kakao.com/v2/local/geo/coord2regioncode.json?x=${longitude}&y=${latitude}`, {
headers: {
Authorization: `KakaoAK ${kakaoApiKey}`,
},
});
const data = response.data;
const nowLocationCity = data.documents.length > 0 ? data.documents[0].region_1depth_name : 'unknown';
const nowLocationGu = data.documents.length > 0 ? data.documents[0].region_2depth_name : 'unknown';
setLocation(
{
...location,
latitude,
longitude,
nowLocationCity,
nowLocationGu,
}
);
} catch (error) {
setLocation({
...location,
error: 'kakao API 호출 실패',
});
}
};
useEffect(() => {
// dispatch(getLocation(loading))
// setTimeout(() => {
// }, 500);
dispatch(getLocation(location))
}, [location])
return location;
};
export default useLocationHook;
useLocationHook은 현재 위치의 위도와 경도를 가져온 후 성공 시에 kakao api에 매개변수로 전달하여 return 하는 방식이다.
return 하기 전에 dispatch로 Redux로 전역관리하는 slice에 location 객체가 저장된다.
getLocation(state, action) {
const { nowLocationCity, nowLocationGu, latitude, longitude } = action.payload
state.location.nowLocationCity = nowLocationCity
state.location.nowLocationGu = nowLocationGu
state.location.nowLatitude = latitude
state.location.nowLongitude = longitude
},

2) 현재 위치의 날씨
현재 위치의 날씨를 구하기 위해 hook을 하나만 만들려 했지만 코드가 상위부터 읽히는 것이 아닌 전체가 한 번에 읽히는 react 특성상 위경도를 XY좌표로 변환하는 hook과 XY좌표를 기준으로 날씨를 출력하는 hook을 나누었다.
* 실무, 고수들은 위치와 날씨를 가져올 때 hook을 사용하는지, hook을 나처럼 나누어 사용하는지 혹은 hook을 사용하지 않고 다른 방법(class 등)으로 하는지 아직 잘 모르겠다.
이번 프로젝트를 진행하면서 가장 어려웠던 부분이다. 비동기 / Axios, 전역변수 / Redux, hook이 처리되 후 실행되어야 하는 함수 및 다음 hook / useEffect 등등 배운 내용 + 구글링 하여 습득한 지식으로 진행하다 보니 코드도 무거워지고 비효율적으로 돌아가는 것 같다.
import { useState } from 'react';
import { useDispatch } from 'react-redux';
import { getConvert } from '../store/modules/acountSlice';
import { useEffect } from 'react';
const useConvertHook = (v1, v2) => {
const dispatch = useDispatch()
const RE = 6371.00877;
const GRID = 5.0;
const SLAT1 = 30.0;
const SLAT2 = 60.0;
const OLON = 126.0;
const OLAT = 38.0;
const XO = 43;
const YO = 136;
const [convertXY, setConvertXY] = useState({ x: 0, y: 0 })
const toXY = (v1, v2) => {
let DEGRAD = Math.PI / 180.0;
let RADDEG = 180.0 / Math.PI;
let re2 = RE / GRID;
let slat3 = SLAT1 * DEGRAD;
let slat4 = SLAT2 * DEGRAD;
let olon2 = OLON * DEGRAD;
let olat2 = OLAT * DEGRAD;
const xy = {}
let sn = Math.tan(Math.PI * 0.25 + slat4 * 0.5) / Math.tan(Math.PI * 0.25 + slat3 * 0.5);
sn = Math.log(Math.cos(slat3) / Math.cos(slat4)) / Math.log(sn);
let sf = Math.tan(Math.PI * 0.25 + slat3 * 0.5);
sf = Math.pow(sf, sn) * Math.cos(slat3) / sn;
let ro = Math.tan(Math.PI * 0.25 + olat2 * 0.5);
ro = re2 * sf / Math.pow(ro, sn);
xy['lat'] = v1;
xy['lng'] = v2;
let ra = Math.tan(Math.PI * 0.25 + v1 * DEGRAD * 0.5);
ra = re2 * sf / Math.pow(ra, sn);
let theta = v2 * DEGRAD - olon2;
if (theta > Math.PI) theta -= 2.0 * Math.PI;
if (theta < -Math.PI) theta += 2.0 * Math.PI;
theta *= sn;
xy['x'] = Math.floor(ra * Math.sin(theta) + XO + 0.5);
xy['y'] = Math.floor(ro - ra * Math.cos(theta) + YO + 0.5);
setConvertXY({ x: xy.x, y: xy.y })
};
useEffect(() => {
toXY(v1, v2);
}, [v1, v2]);
useEffect(()=>{
dispatch(getConvert(convertXY));
},[convertXY])
return convertXY;
}
export default useConvertHook;
위경도를 기상청 API에 사용 가능한 XY좌표로 변환해 주는 hook
import { useEffect, useState } from 'react';
import axios from 'axios';
import { useDispatch, useSelector } from 'react-redux';
import { getWeather } from '../store/modules/acountSlice';
const useWeatherHook = () => {
const dispatch = useDispatch()
const { nowX, nowY } = useSelector(state => state.acount.location)
// console.log(nowX, nowY);
const [weatherData, setWeatherData] = useState()
const setWeather = async () => {
const KMAAPikey = 'apikey'
const now = new Date();
let year = now.getFullYear();
let month = now.getMonth() + 1;
let day = now.getDate();
let hours = now.getHours();
let minutes = now.getMinutes();
month = month < 10 ? '0' + month : month;
day = day < 10 ? '0' + day : day;
hours = hours -1;
if (hours < 0) {
now.setDate(now.getDate() - 1);
year = now.getFullYear();
month = now.getMonth() + 1;
day = now.getDate();
hours = 24 + hours;
}
hours = hours < 10 ? '0' + hours : hours;
minutes = '00';
const baseDate = `${year}${month}${day}`;
const baseTime = `${hours}${minutes}`;
const dataType = 'JSON';
try {
const response = await axios.get(
`http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtFcst?serviceKey=${KMAAPikey}&pageNo=1&numOfRows=1000&dataType=${dataType}&base_date=${baseDate}&base_time=${baseTime}&nx=${nowX}&ny=${nowY}`
);
const weatherItem = response.data.response.body.items.item
const tem = weatherItem.find(item => item.category === 'T1H')
const sky = weatherItem.find(item => item.category === 'SKY')
const pty = weatherItem.find(item => item.category === 'PTY')
setWeatherData({tem, sky, pty});
} catch (error) {
// console.error('--- ERROR ---', error);
}
};
useEffect(() => {
setWeather();
}, [nowX, nowY]);
useEffect(() => {
if(weatherData){
dispatch(getWeather(weatherData))
}
}, [weatherData]);
return weatherData
}
export default useWeatherHook;
현재 시간을 기준으로 적절하게 조정하여 API를 호출하였다.
호출시 현재 온도와 날씨만 필요하므로 해당 url을 get 하고 filtering 하여 weatherData에 넣었다.



그 결과 현재 날씨의 상태와 기온을 잘 가져올 수 있었다.