하소연 먼저 시작하겠다.....
현재 혼자서 리액트 사이드 프로젝트 진행중에 있다.
해당 프로젝트에서 geolocation api를 통해 사용자의 위도 경도를 받아낸 후
받아온 위도 경도를 reversegeocoding하여 사용자의 주소까지 가져오는 커스텀 훅을 만들던 중이였다.
내가 원하는 로직은 이렇다.
1. 사용자의 위도 경도를 받아온다.
2. 받아온 위도 경도 값을 reversegeocoding하는 함수에 삽입하여 주소값을 얻어낸다.
해당 로직대로 구현하였을 때 위도 경도는 잘 받아오지만 위도 경도를 props로 받아서 reversegeocoding할 때
return을 할 경우 원하는 값이 반환되는게 아닌 promise<pending> 값을 던져주더라 ....
* promise<pending>은 pending 뜻 그대로 이행하거나 거부되지 않은 초기 상태를 뜻한다.
내가 해당 문제를 해결하는데 시간이 오래 걸린 이유는 간단하다."react와 javascript를 자세히 몰랐다."
문제가 발생한 원인은 의외로 간단하였다.
위도 경도 값을 반환해주는 로직을 돌고 결과 값이 반환 되고 주소값을 변환해주는 로직으로 들어가야하는데
위도 경도 값을 반환해주는 로직을 돌고 결과 값이 반환 되기도 전에 주소값을 변환해주는 로직으로 들어가버리다보니
promise<pending> 이라는 값을 반환한것이였다.
간단하게 말하면 A 끝나기도 전에 B 시도해서 그렇다.
다들 잘 기억하자
"자바스크립트에서 async/await 사용 시 동일한 스코프에서 await하지 않으면 앞서 실행한 async를 기다려주지 않는다."
에러 해결 전 후 코드를 첨부 하겠다.
(타입 수정)
❗ 전
import { useState, useEffect } from 'react';
import axios from 'axios';
interface locationType {
loaded: boolean;
coordinates?: {
lat: number;
lng: number;
address: string;
};
error?: { code: number; message: string };
}
async function mapAPI(latitude: unknown, longitude: unknown) {
try {
const response = await axios
.get(
`https://dapi.kakao.com/v2/local/geo/coord2address.json?input_coord=WGS84&x=${latitude}&y=${longitude}`,
{
headers: {
Authorization: 'KakaoAK ',
},
}
)
.then((response: { data: { documents: unknown[] } }) => {
const location: any = response.data.documents[0];
const si = location.address.region_1depth_name;
const gu = location.address.region_2depth_name;
return `${si} ${gu}`;
});
} catch (error: any) {
console.log(error.message);
}
}
const useGeolocation = () => {
const [userlocation, setUserLocation] = useState<string | any>('');
const [location, setLocation] = useState<locationType>({
loaded: false,
coordinates: { lat: 0, lng: 0, address: '' },
});
// 성공에 대한 로직
const onSuccess = (location: {
coords: { latitude: number; longitude: number };
}) => {
const address = mapAPI(129.1231357, 35.1678779);
console.log(address);
setLocation({
loaded: true,
coordinates: {
lat: location.coords.latitude,
lng: location.coords.longitude,
address: 'bye',
},
});
};
// 에러에 대한 로직
const onError = (error: { code: number; message: string }) => {
setLocation({
loaded: true,
error,
});
};
useEffect(() => {
// navigator 객체 안에 geolocation이 없다면
// 위치 정보가 없는 것.
if (!('geolocation' in navigator)) {
onError({
code: 0,
message: 'Geolocation not supported',
});
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
}, []);
return location;
};
export default useGeolocation;
❗ 후
import { useState, useEffect } from 'react';
import axios from 'axios';
interface Coordinates {
lat: number;
lng: number;
address: string;
}
interface Location {
loaded: boolean;
coordinates?: Coordinates;
error?: {
code: number;
message: string;
};
}
interface ResponseData {
documents: {
address: {
region_1depth_name: string;
region_2depth_name: string;
};
}[];
}
const mapAPI = async (latitude: number, longitude: number) => {
try {
const response = await axios.get<ResponseData>(
`https://dapi.kakao.com/v2/local/geo/coord2address.json?input_coord=WGS84&x=${latitude}&y=${longitude}`,
{
headers: {
Authorization: 'KakaoAK 488de47883695ba1806e3203af90422a',
},
}
);
const location = response.data.documents[0];
const { region_1depth_name: si, region_2depth_name: gu } = location.address;
return `${si} ${gu}`;
} catch (error: any) {
console.log(error.message);
return '';
}
};
const useGeolocation = (): Location => {
const [location, setLocation] = useState<Location>({
loaded: false,
coordinates: {
lat: 0,
lng: 0,
address: 'Suyeong-gu, Busan',
},
});
useEffect(() => {
const onSuccess = async (position: GeolocationPosition) => {
const { latitude, longitude } = position.coords;
// const address = await mapAPI(latitude, longitude);
const address = await mapAPI(129.1284061294, 35.1740102455);
setLocation({
loaded: true,
coordinates: {
lat: latitude,
lng: longitude,
address,
},
});
};
const onError = (error: GeolocationPositionError) => {
setLocation({
loaded: true,
error: {
code: error.code,
message: error.message,
},
});
};
if (!navigator.geolocation) {
onError({
code: 0,
message: 'Geolocation not supported',
PERMISSION_DENIED: 0,
POSITION_UNAVAILABLE: 0,
TIMEOUT: 0,
});
} else {
navigator.geolocation.getCurrentPosition(onSuccess, onError);
}
}, []);
return location;
};
export default useGeolocation;
차이점은 직접 알아내보도록 하자 ..
별거 아닌 문제였지만 근본적인 문제를 몰랐던 나에게는 해당 부분을 해결하는데 정말 힘들었다.
리액트를 공부하며 느끼는 점이 리액트를 쓸 때는 코드를 구현해가는 것도 중요하지만 리액트가 어떤 아이이고
어떻게 흘러가고 등등 생각한거보다 더 태초적인거 부터 알 필요가 있다고 느꼈다.
그리고 자바스크립트도 생각보다 더 깊게 알아야하고 더 근본적인것 부터 많이 공부해야하는거 같다.
난 이 사실을 간과한채 그냥 코드를 투닥투닥 적기만 했다....
물론 그냥 일단 돌아가기만 가는 코드나 찍어내는 인간 공장마냥 해도 되지만 난 그게 싫다.
난 내일의 변경사항도 대응할 수 있으며 유지보수가 용이하고 응집도가 높고 결합도가 낮은 클린한 코드를 짜고싶다.
혼자하는 리액트 첫 사이드 프로젝트는 좋은 결과물을 만들어내는것도 당연한 목표겠지만
프로젝트 기간이 얼마가 걸리든간에 리액트의 세세한 부분까지 직접 부딪히고 부딪힐 때 마다 어떻게 헤쳐나갔었는지 항시 기억하여 미래에 거름이 될만한 좋은 깨달음을 얻는것에 초점을 맞추어 해당 부분을 더 중요한 목표로 삼고자한다.
끝 !
'자바스크립트 - React.js' 카테고리의 다른 글
[React.js] 커스텀 훅(Custom Hook)과 유틸 함수(util function)에 대해서 (0) | 2023.03.16 |
---|---|
[React.js] Geolocation과 reverseGeocoding을 활용한 사용자 현재 위치 기반 좌표, 주소값 받아오기 (0) | 2023.02.17 |
[React.js] 리액트에서 자주 쓰는 if문 작성 패턴 5개 (0) | 2022.12.19 |
[React.js] 컴포넌트간 편리한 state 공유를 위한 Redux (0) | 2022.12.15 |
[React.js] 성능개선 3 : useTransition, useDeferredValue (0) | 2022.12.07 |