반응형
Vite React Kakao Map
Vite React Daum Address Api
이번 글을 통해 배워갈 내용
- 개요
- 기초세팅
- 리액트 카카오맵 다음지도 연동 컴포넌트
- 리액트 카카오맵
- 리액트 다음지도 API
개요
해당 프로젝트는 리액트에
카카오맵과 다음 지도 연동 기능을 같이 추가한 다음
연동해서 활용하는 미니 프로젝트입니다|
주소를 선택하면
지도에 자동으로 선택되는 컴포넌트를 만들었습니다
기초세팅
(카카오 데브에서 가입, CORS 등에 세팅은 스킵합니다)
먼저 카카오 Developers를 방문해서
자바스크립트 키를 찾습니다
1-1 env 파일에 환경변수를 추가해 줍니다
VITE_KAKAOMAP_JAVASCRIPT_APP_KEY= "위에 있는 Javascript 키 값"
1-2
index.html 파일에 script 두 개를 추가합니다
<script type="text/javascript" strategy="beforeInteractive" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=%VITE_KAKAOMAP_JAVASCRIPT_APP_KEY%&libraries=services,clusterer,drawing"></script>
<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
1-3
리액트 타입스크립트기반에서
카카오맵과 다음 주소를 쓰기 위해서
kakao.maps.d.ts와 react-daum-postcode를 설치했습니다
https://www.npmjs.com/package/react-daum-postcode
https://www.npmjs.com/package/kakao.maps.d.ts
# react-daum-postcode
# npm
npm install react-daum-postcode
# yarn
yarn add react-daum-postcode
# kakao.maps.d.ts
# npm
npm install kakao.maps.d.ts --save-dev
# yarn
yarn add kakao.maps.d.ts --dev
리액트 카카오맵 다음지도 연동 컴포넌트
AddressInput.tsx
(tailwind 기반으로 만들었습니다)
/**
Comment by CodeMaster KimC
For more information, visit: https://codemasterkimc.tistory.com
*/
import { FC, useState } from 'react';
import DaumAddr, { IAddr, initialAddressInfo } from './DaumAddrInput';
import KakaoMap from './KakaoMapDisplay';
interface IProps {}
const AddressInput: FC<IProps> = ({}) => {
const [kakaoAddr, setKakaoAddr] = useState<IAddr>(initialAddressInfo);
return (
<div>
<label className="block text-sm font-medium text-gray-900 mb-2">도로명 주소</label>
<DaumAddr kakaoAddr={kakaoAddr} setKakaoAddr={setKakaoAddr} />
<KakaoMap kakaoAddr={kakaoAddr} />
</div>
);
};
export default AddressInput;
리액트 카카오맵
KakaoMap.tsx
/**
Comment by CodeMaster KimC
For more information, visit: https://codemasterkimc.tistory.com
*/
import { FC, useEffect, useState } from 'react';
import { IAddr } from './DaumAddrInput';
declare global {
interface Window {
kakao: any;
}
}
interface IProps {
kakaoAddr: IAddr;
}
const KakaoMap: FC<IProps> = ({ kakaoAddr }) => {
const [map, setMap] = useState<any>();
const [marker, setMarker] = useState<any>();
const initMap = () => {
const container = document.getElementById('map');
const options: MapOptions = {
center: new window.kakao.maps.LatLng(37.532600, 127.024612),
level: 3,
draggable: false,
scrollwheel: false,
disableDoubleClick: false,
disableDoubleClickZoom: false,
tileAnimation: false,
keyboardShortcuts: false,
};
setMap(new window.kakao.maps.Map(container, options));
setMarker(new window.kakao.maps.Marker());
};
useEffect(() => {
window.kakao.maps.load(() => initMap());
}, []);
useEffect(() => {
const asyncFn = async () => {
if (!kakaoAddr || kakaoAddr.address === '') return;
try {
const result = await searchAddress(address);
if (result && result.length > 0) {
const { x, y } = result[0];
const currentPos = new window.kakao.maps.LatLng(y, x);
map.panTo(currentPos);
marker.setMap(null);
marker.setPosition(currentPos);
marker.setMap(map);
}
} catch (error) {
console.error('Error occurred during address search:', error);
}
};
asyncFn();
}, [kakaoAddr]);
return (
<div>
<div id="map" style={{ width: '500px', height: '400px' }}></div>
</div>
);
};
export default KakaoMap;
function searchAddress(address: string): Promise<gcAdrSrchResult[]> {
return new Promise((resolve, reject) => {
const geocoder = new window.kakao.maps.services.Geocoder();
geocoder.addressSearch(address, (result: gcAdrSrchResult[], status: string) => {
if (status === window.kakao.maps.services.Status.OK && result?.length > 0) {
resolve(result);
} else {
reject(new Error('Address search failed or no results found'));
}
});
});
}
interface MapOptions {
center: { latitude: number; longitude: number };
level: number;
mapTypeId?: number;
draggable?: boolean;
scrollwheel?: boolean;
disableDoubleClick?: boolean;
disableDoubleClickZoom?: boolean;
projectionId?: string;
tileAnimation?: boolean;
keyboardShortcuts?: boolean | object;
speed?: number;
}
interface gcAdrSrchResult {
address: {
address_name: string;
b_code: string;
h_code: string;
main_address_no: string;
mountain_yn: string;
region_1depth_name: string;
region_2depth_name: string;
region_3depth_h_name: string;
region_3depth_name: string;
sub_address_no: string;
x: string;
y: string;
};
address_name: string;
address_type: string;
road_address: {
address_name: string;
building_name: string;
main_building_no: string;
region_1depth_name: string;
region_2depth_name: string;
region_3depth_name: string;
road_name: string;
sub_building_no: string;
underground_yn: string;
x: string;
y: string;
zone_no: string;
};
x: string;
y: string;
}
리액트 다음지도 API
DaumAddrInput.tsx
/**
Comment by CodeMaster KimC
For more information, visit: https://codemasterkimc.tistory.com
*/
import { FC } from 'react';
interface IProps {
kakaoAddr: IAddr;
setKakaoAddr: React.Dispatch<React.SetStateAction<IAddr>>;
}
const DaumAddrInput: FC<IProps> = ({ kakaoAddr, setKakaoAddr }) => {
const onClickAddr = () => {
new window.daum.Postcode({
oncomplete: function (data: IAddr) {
setKakaoAddr(data);
console.log(data);
document.getElementById('addrDetail')?.focus();
},
}).open();
};
if (kakaoAddr.address) {
return (
<div className="text-white bg-blue-400" onClick={onClickAddr}>
{kakaoAddr.address}
</div>
);
}
return (
<button type="button" className="w-16 p-2 text-white bg-slate-300" onClick={onClickAddr}>
주소 찾기
</button>
);
};
export default DaumAddrInput;
export interface IAddr {
address: string;
addressEnglish: string;
addressType: string;
apartment: string;
autoJibunAddress: string;
autoJibunAddressEnglish: string;
autoRoadAddress: string;
autoRoadAddressEnglish: string;
bcode: string;
bname: string;
bname1: string;
bname1English: string;
bname2: string;
bname2English: string;
bnameEnglish: string;
buildingCode: string;
buildingName: string;
hname: string;
jibunAddress: string;
jibunAddressEnglish: string;
noSelected: string;
postcode: string;
postcode1: string;
postcode2: string;
postcodeSeq: string;
query: string;
roadAddress: string;
roadAddressEnglish: string;
roadname: string;
roadnameCode: string;
roadnameEnglish: string;
sido: string;
sidoEnglish: string;
sigungu: string;
sigunguCode: string;
sigunguEnglish: string;
userLanguageType: string;
userSelectedType: string;
zonecode: string;
}
declare global {
export interface Window {
daum: any;
}
}
export const initialAddressInfo: IAddr = {
address: '',
addressEnglish: '',
addressType: '',
apartment: '',
autoJibunAddress: '',
autoJibunAddressEnglish: '',
autoRoadAddress: '',
autoRoadAddressEnglish: '',
bcode: '',
bname: '',
bname1: '',
bname1English: '',
bname2: '',
bname2English: '',
bnameEnglish: '',
buildingCode: '',
buildingName: '',
hname: '',
jibunAddress: '',
jibunAddressEnglish: '',
noSelected: '',
postcode: '',
postcode1: '',
postcode2: '',
postcodeSeq: '',
query: '',
roadAddress: '',
roadAddressEnglish: '',
roadname: '',
roadnameCode: '',
roadnameEnglish: '',
sido: '',
sidoEnglish: '',
sigungu: '',
sigunguCode: '',
sigunguEnglish: '',
userLanguageType: '',
userSelectedType: '',
zonecode: '',
};
참조
https://apis.map.kakao.com/web
https://codemasterkimc.tistory.com/50
반응형
'Javascript > React' 카테고리의 다른 글
react-alert 대신 react-toastify 사용해서 알림 표시해보기 (0) | 2023.10.05 |
---|---|
React에 Redux Toolkit 사용해보기 Typescript Vite (0) | 2023.10.05 |
React에 카카오 지도 넣는 방법 (초간단) (Client Side Render) (0) | 2023.06.18 |
React로 이미지 업로드 및 필터 적용하고 출력해보기 (0) | 2022.11.19 |
TypeScript와 함께 useReducer를 사용하는 방법 (0) | 2022.07.16 |