카카오 지도 api를 이용해 검색한 키워드와 관련된 결과를 지도에 마커로 찍어주는 기능을 만들어봤다.
1. 카카오 개발자 페이지에서 api key 발급
2. 도메인 등록
메뉴의 플랫폼 -> Web에서 기본 도메인으로 http://localhost:3000을 등록해준다.
3. .env 파일을 만들어 key값 따로 저장
이 때 변수명은 꼭 REACT_APP으로 시작하도록 지어줘야 한다.
그리고 꼭 자바스크립트 키를 넣어줘야 한다!
모든 권한을 갖고 있다길래 Admin 키로 했었는데 계속 안되서 설마하고 자바스크립트 키로 했더니 됐다.
REACT_APP_KAKAO_KEY=카카오 지도 API 자바스크립트 키
4. react-kakao-maps-sdk 설치
yarn add react-kakao-maps-sdk
5. script 태그 추가
public폴더 안의 index.html의 head태그 안에 아래 내용을 추가해준다.
appkey부분에 본인의 키를 넣어주면 되는데, 아까 .env 파일에 추가해줬기 때문에 %로 감싼 키 이름을 넣어주면 된다.
<script
type="text/javascript"
src="//dapi.kakao.com/v2/maps/sdk.js?appkey=%REACT_APP_KAKAO_KEY%&libraries=services,clusterer"
></script>
6. tsconfig.json의 compilerOptions안에 types 추가
"compilerOptions": {
//...
"types": [
"kakao.maps.d.ts",
],
}
이제 본격적으로 시작!~!
기본적으로 이 사이트의 예제를 따라서 만들었는데 타입때문에 꽤나 고생을 많이 했다. (같이 보면서 안되는 부분만 참고해주시길 바랍니당)
https://react-kakao-maps-sdk.jaeseokim.dev/docs/sample/library/keywordBasic
index.tsx
const [info, setInfo] = useState<IMarker>()
const [markers, setMarkers] = useState<IMarker[]>()
const [map, setMap] = useState<kakao.maps.Map>()
address.d.ts
export interface IMarker {
position: {
lat: number
lng: number
}
content: string
}
info와 markers를 따로 IMarker라는 타입을 추가해주고 useState의 타입으로 지정해주었다.
index.tsx
본격 맵을 그려주는 부분.
return (
<div>
<Map
center={{
lat: 37.566826,
lng: 126.9786567,
}}
style={{
width: '100%',
height: '350px',
}}
level={3}
onCreate={setMap}
>
{markers?.map((marker) => (
<MapMarker
key={`marker-${marker.content}-${marker.position.lat},${marker.position.lng}`}
position={marker.position}
onClick={() => setInfo(marker)}
>
{info && info.content === marker.content && <div style={{ color: '#000' }}> {marker.content}</div>}
</MapMarker>
))}
</Map>
<form onSubmit={handleFormSubmit} style={{ marginLeft: '500px' }}>
<input type='text' placeholder='장소를 입력하세요' value={inputVal} onChange={handleInputChange} />
<button type='submit'>검색</button>
</form>
</div>
)
input과 submit 이벤트 핸들러. submit이 되면 getSearchResults라는 함수를 실행해 검색 결과가 markers배열에 들어가도록 했다.
const [inputVal, setInputVal] = useState('')
const handleInputChange = (e: FormEvent<HTMLInputElement>) => {
setInputVal(e.currentTarget.value)
}
const handleFormSubmit = (e: FormEvent) => {
e.preventDefault()
getSearchResults(inputVal)
}
제일 중요한 부분! 키워드 검색을 하는 부분이다.
const getSearchResults = (searchWord: string) => {
if (!map) return
const ps = new kakao.maps.services.Places()
ps.keywordSearch(searchWord, (data, status, _pagination) => {
if (status === kakao.maps.services.Status.OK) {
const bounds = new kakao.maps.LatLngBounds()
const tmpMarkers: IMarker[] = []
data.forEach((d) => {
tmpMarkers.push({
position: {
lat: Number(d.y),
lng: Number(d.x),
},
content: d.place_name,
})
bounds.extend(new kakao.maps.LatLng(Number(d.y), Number(d.x)))
})
setMarkers(tmpMarkers)
map.setBounds(bounds)
}
})
}
admin키로 계속 삽질하고 타입때문에 계속 삽질한 덕분에 뭔가 진척이 없었는데 그래도 하고 싶었던 기능을 추가하게 되어서 뿌듯하다 😊😊😊
혹시 모르니 전체 코드!
import { useState, FormEvent } from 'react'
import { Map, MapMarker } from 'react-kakao-maps-sdk'
import { IMarker } from 'types/address'
const Home = () => {
const [info, setInfo] = useState<IMarker>()
const [markers, setMarkers] = useState<IMarker[]>()
const [map, setMap] = useState<kakao.maps.Map>()
const [inputVal, setInputVal] = useState('')
const getSearchResults = (searchWord: string) => {
if (!map) return
const ps = new kakao.maps.services.Places()
ps.keywordSearch(searchWord, (data, status, _pagination) => {
if (status === kakao.maps.services.Status.OK) {
const bounds = new kakao.maps.LatLngBounds()
const tmpMarkers: IMarker[] = []
data.forEach((d) => {
tmpMarkers.push({
position: {
lat: Number(d.y),
lng: Number(d.x),
},
content: d.place_name,
})
bounds.extend(new kakao.maps.LatLng(Number(d.y), Number(d.x)))
})
setMarkers(tmpMarkers)
map.setBounds(bounds)
}
})
}
const handleInputChange = (e: FormEvent<HTMLInputElement>) => {
setInputVal(e.currentTarget.value)
}
const handleFormSubmit = (e: FormEvent) => {
e.preventDefault()
getSearchResults(inputVal)
}
return (
<div>
<Map
center={{
lat: 37.566826,
lng: 126.9786567,
}}
style={{
width: '100%',
height: '350px',
}}
level={3}
onCreate={setMap}
>
{markers?.map((marker) => (
<MapMarker
key={`marker-${marker.content}-${marker.position.lat},${marker.position.lng}`}
position={marker.position}
onClick={() => setInfo(marker)}
>
{info && info.content === marker.content && <div style={{ color: '#000' }}> {marker.content}</div>}
</MapMarker>
))}
</Map>
<form onSubmit={handleFormSubmit} style={{ marginLeft: '500px' }}>
<input type='text' placeholder='장소를 입력하세요' value={inputVal} onChange={handleInputChange} />
<button type='submit'>검색</button>
</form>
</div>
)
}
export default Home
'Education > Wanted Pre-Onboarding FE Course' 카테고리의 다른 글
원티드 프리온보딩 프론트엔드 코스 회고 (0) | 2022.07.08 |
---|---|
[TIL] 22.05.31 프리온보딩 Day 20 (0) | 2022.05.31 |
[TIL] 22.05.29 프리온보딩 Day 19 - HTML dataset 이용하기(+react) (0) | 2022.05.30 |
[TIL] 22.05.26 프리온보딩 Day 18 - Squash and merge (0) | 2022.05.27 |
[TIL] 22.05.24 프리온보딩 Day 16 (0) | 2022.05.25 |