장소 검색 결과를 카카오 지도에 나타내기
이전 포스팅에서는 카카오 지도API를 통해 화면에 띄웠었다. 이번에는 장소를 input 값으로 받아 해당 장소를 카카오 지도에 띄우고 마커로 표시해보자.
https://gingerkang.tistory.com/65
카카오 지도 라이브러리
장소 검색을 하기 위해 services 라이브러리를 사용할 것이다.
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=APIKEY&libraries=LIBRARY"></script>
지도 API를 불러오기 위해 head 태그 안에 삽입해놨던 script 태그에 위와 같이 libraries를 추가하여 준다. LIBRARY에 사용할 라이브러리 이름(services)을 넣어준다.
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=APIKEY&libraries=services"></script>
이제 장소 검색 서비스를 이용해보자. 장소 검색 객체를 생성하고 검색 결과 완료시 호출되는 콜백함수를 MapContainer.js의 useEffect 안에 넣어주자.
// 장소 검색 객체를 생성
const ps = new kakao.maps.services.Places();
// 키워드로 장소를 검색
ps.keywordSearch('입력 값', placesSearchCB);
// 키워드 검색 완료 시 호출되는 콜백함수
function placesSearchCB (data, status, pagination) {
if (status === kakao.maps.services.Status.OK) {
// 검색된 장소 위치를 기준으로 지도 범위를 재설정하기위해
// LatLngBounds 객체에 좌표를 추가
let bounds = new kakao.maps.LatLngBounds();
for (let i=0; i<data.length; i++) {
displayMarker(data[i]);
bounds.extend(new kakao.maps.LatLng(data[i].y, data[i].x));
}
// 검색된 장소 위치를 기준으로 지도 범위를 재설정
map.setBounds(bounds);
}
}
그리고 지도에 입력 값에 대한 마커를 표시하기 위해 displayMarker 함수도 추가해준다.
// 지도에 마커를 표시하는 함수
function displayMarker(place) {
// 마커를 생성하고 지도에 표시
let marker = new kakao.maps.Marker({
map: map,
position: new kakao.maps.LatLng(place.y, place.x)
});
// 마커에 클릭이벤트를 등록
kakao.maps.event.addListener(marker, 'click', function() {
// 마커를 클릭하면 장소명이 인포윈도우에 표출
infowindow.setContent('<div style="padding:5px;font-size:12px;">' + place.place_name + '</div>');
infowindow.open(map, marker);
});
}
MapContainer.js
// MapContainer.js
import React, { useEffect } from 'react';
const { kakao } = window;
const MapContainer = () => {
useEffect(() => {
const container = document.getElementById('myMap');
const options = {
center: new kakao.maps.LatLng(33.450701, 126.570667),
level: 3
};
const map = new kakao.maps.Map(container, options);
const ps = new kakao.maps.services.Places();
ps.keywordSearch('입력 값', placesSearchCB);
function placesSearchCB (data, status, pagination) {
if (status === kakao.maps.services.Status.OK) {
let bounds = new kakao.maps.LatLngBounds();
for (let i=0; i<data.length; i++) {
displayMarker(data[i]);
bounds.extend(new kakao.maps.LatLng(data[i].y, data[i].x));
}
map.setBounds(bounds);
}
}
function displayMarker(place) {
let marker = new kakao.maps.Marker({
map: map,
position: new kakao.maps.LatLng(place.y, place.x)
});
}
}, []);
return (
<div id='myMap' style={{
width: '500px',
height: '500px'
}}></div>
);
}
export default MapContainer;
// 마커에 클릭이벤트를 등록
kakao.maps.event.addListener(marker, 'click', function() {
// 마커를 클릭하면 장소명이 인포윈도우에 표출
infowindow.setContent('<div style="padding:5px;font-size:12px;">' + place.place_name + '</div>');
infowindow.open(map, marker);
});
위의 코드는 마커를 클릭 했을 때 장소 이름을 나타내는 코드인데, 나는 필요 없어서 뺐다. 필요한 분들은 그냥 위의 코드 그대로 넣고 지도를 담는 container를 선언한 곳 위에 다음 코드만 작성해주면 된다.
let infowindow = new kakao.maps.InfoWindow({zIndex:1});
간단하게 지도에 입력 받은 값을 표시할 준비가 끝났다. 이제 input을 받을 component를 하나 만들어주자.
SearchPlace.js
// SearchPlace.js
import React, { useState } from "react";
import MapContainer from "./MapContainer";
const SearchPlace = () => {
const [inputText, setInputText] = useState("");
const [place, setPlace] = useState("");
const onChange = (e) => {
setInputText(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
setPlace(inputText);
setInputText("");
};
return (
<>
<form className="inputForm" onSubmit={handleSubmit}>
<input
placeholder="Search Place..."
onChange={onChange}
value={inputText}
/>
<button type="submit">검색</button>
</form>
<MapContainer searchPlace={place} />
</>
);
};
export default SearchPlace;
위와 같이 입력을 받고 그 값을 inputText에 저장을 한 후, 한눈에 보기 쉽게 submit이 되면 place에 담아 MapContainer에 props로 전달한다. MapContainer에서 props를 받아오기 위해 아래와 같이 코드를 수정한다.
const MapContainer = ({ searchPlace }) => {
...
}
근데 이때 문제가 있다. 이대로 실행을 시키면 useEffect의 두 번째 파라미터가 []로 되어 있어 렌더링이 되지 않을 것 이다. 그렇다고 []를 없애면 MapContainer가 SearchPlace 컴포넌트 안에 있어 inputText 상태가 바뀔 때 마다 렌더링이 계속 될 것이다. 이를 방지하기 위해 MapContainer 안에 있는 useEffect 두 번째 파라미터 [] 안에 searchPlace를 넣어준다. 그러면 지도는 검색 결과가 바뀔 때만 렌더링을 다시 할 것이다.
MapContainer.js
// MapContainer.js
...
const MapContainer = ({ searchPlace }) => {
useEffect(() => {
const container = document.getElementById("myMap");
const options = {
center: new kakao.maps.LatLng(33.450701, 126.570667),
level: 3,
};
const map = new kakao.maps.Map(container, options);
const ps = new kakao.maps.services.Places();
ps.keywordSearch(searchPlace, placesSearchCB);
function placesSearchCB(data, status, pagination) {
if (status === kakao.maps.services.Status.OK) {
let bounds = new kakao.maps.LatLngBounds();
for (let i = 0; i < data.length; i++) {
displayMarker(data[i]);
bounds.extend(new kakao.maps.LatLng(data[i].y, data[i].x));
}
map.setBounds(bounds);
}
}
function displayMarker(place) {
let marker = new kakao.maps.Marker({
map: map,
position: new kakao.maps.LatLng(place.y, place.x),
});
}
}, [searchPlace]);
...
'React' 카테고리의 다른 글
[React] TypeScript와 ESLint, Prettier 설정하기 (4) | 2020.10.11 |
---|---|
[React] scroll 이벤트 리스너 unmounted 처리 (0) | 2020.07.06 |
[React] 함수형 컴포넌트에서 카카오 지도 API 사용하기 (21) | 2020.06.13 |
[React] styled-components 다크 모드 (+Typescript) (0) | 2020.06.10 |
[React] 맥북에서 AWS CLI 환경변수 설정하기 (0) | 2020.06.10 |