다음 토이프로젝트의 개발 기록이다.
Kakao 지도 API, react-kakao-maps-sdk, Kakao Local API, 공공 data 포털을 활용했다.
입력을 할 때마다 연관 검색어가 자동으로 뜨게끔 하는 기능은 어렵지 않게 찾아볼 수 있는 기능이다. 카카오 Local API를 활용한 자동 완성을 구현해보자.
import { set } from 'date-fns';
import { useState, useCallback } from 'react';
const useAutoSearch = () => {
const [isAutoSearch, setIsAutoSearch] = useState<boolean>(false);
const [searchWord, setSearchWord] = useState<string>('');
const [searchAutoList, setSearchAutoList] = useState<string[]>([]);
const [focusIndex, setFocusIndex] = useState(-1);
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement>) => {
e.preventDefault();
const value = e.target.value;
setSearchWord(value);
if (value.length) {
const ps = new kakao.maps.services.Places();
ps.keywordSearch(value, (data, status, pagination) => {
if (status === kakao.maps.services.Status.OK) {
const list = data.map((item: any) => item.place_name).slice(0, 5);
setSearchAutoList(list);
setIsAutoSearch(true);
setFocusIndex(-1);
} else {
setIsAutoSearch(false);
}
});
} else setIsAutoSearch(false);
};
const handleChangeFocus = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'ArrowDown') {
const index = (focusIndex + 1) % searchAutoList.length;
setFocusIndex(index);
} else if (e.key === 'ArrowUp') {
const index = (focusIndex - 1 + searchAutoList.length) % searchAutoList.length;
setFocusIndex(index);
} else if (e.key === 'Enter') {
e.preventDefault();
if (!isAutoSearch) return;
setSearchWord(searchAutoList[focusIndex]);
setIsAutoSearch(false);
setSearchAutoList([]);
setFocusIndex(-1);
}
};
const onClickAutoGroup = (place: string) => {
setSearchWord(place);
setIsAutoSearch(false);
setSearchAutoList([]);
};
const onClickSearchButton = () => {
setSearchWord('');
setIsAutoSearch(false);
};
return {
isAutoSearch,
searchWord,
searchAutoList,
focusIndex,
handleChangeInput,
handleChangeFocus,
onClickSearchButton,
onClickAutoGroup,
};
};
export default useAutoSearch;
import { useState, useRef, useCallback } from 'react';
import { Map, MapMarker } from 'react-kakao-maps-sdk';
import { LoadingState } from '@src/Component';
import { useKakaoLoader, useMapMarker, useAutoSearch } from '@src/Hook';
import { Form, Button, ListGroup } from 'react-bootstrap';
import styled from 'styled-components';
const MapPage = () => {
const {
isAutoSearch,
searchWord,
searchAutoList,
focusIndex,
handleChangeInput,
handleChangeFocus,
onClickSearchButton,
onClickAutoGroup,
} = useAutoSearch();
const mapRef = useRef<kakao.maps.Map>(null);
const [curPage, setCurPage] = useState<number>(1);
const [maxPage, setMaxPage] = useState<number>(1);
const insertAddress = () => {
setCurPage(1);
searchPlaces(searchWord, 1, setMaxPage);
onClickSearchButton();
};
return (
<MapContainer>
<FormContainer>
<Form>
<Form.Control
size='lg'
type='text'
placeholder='날씨를 알고 싶은 장소는?'
value={searchWord}
onChange={handleChangeInput}
onKeyDown={handleChangeFocus}
/>
</Form>
<Button onClick={insertAddress}>확인</Button>
</FormContainer>
{isAutoSearch && (
<ListGroupContainer>
<ListGroup>
{searchAutoList.map((item: string, index: number) => (
<ListGroup.Item
className={`${focusIndex === index && 'focus'}`}
key={'searchAutoList' + index}
onClick={() => onClickAutoGroup(item)}
>
{item}
</ListGroup.Item>
))}
</ListGroup>
</ListGroupContainer>
)}
</MapContainer>
);
};
export default MapPage;