[리액트] 검색창 자동완성 키보드 이동

임승민·2022년 11월 11일
3

React 기능구현

목록 보기
6/6
post-custom-banner

검색 사이트들을 보면 검색어를 입력하면 그와 관련된 추천 검색어들이 하단에 표시된다.

그럼 위아래 방향키를 통해 원하는 검색어로 이동을 하는데 이 기능을 구현해 볼 것이다.

💡 구현목표
1. 위아래 방향키로 추천 검색어 이동
2. enter로 input창의 검색어 추천 검색어로 변경



추천 검색어 접근 방식

recWord.map((item: RecObj, idx: number) => {
	return (
		<S.RecItem key={item.sickCd} focus={focusIdx === idx}>
			{item.sickNm}
		</S.RecItem>
	);
})

const [focusIdx, setFocusIdx] = useState(-1);

focusIdx라는 state를 이용해 추천 검색어에 접근할 것이다. 초기값은 -1로 해준다 그래야 방향키를 누르지 않았을 때 검색어에 접근하지 않는다.

focus={focusIdx === idx}

focusIdx와 추천검색어들의 인덱스값을 비교해서 focusIdx === idx가 일치한 경우에 배경색을 줄 것이다.



input창에 KeyDown이벤트 이용하기

const changeIdxNum = (e: React.KeyboardEvent<HTMLInputElement>) => {
		if (e.key === 'ArrowDown') {
			recLength > 0 && recLength < maxList
				? setFocusIdx((prev) => (prev + 1) % recLength)
				: setFocusIdx((prev) => (prev + 1) % maxList);
		}		
		if (e.key === 'ArrowUp') {
			recLength > 0 && recLength < maxList
				? setFocusIdx((prev) => (prev - 1 + recLength) % recLength)
				: setFocusIdx((prev) => (prev - 1 + maxList) % maxList);
		}
		if (e.key === 'Escape') {
			setFocusIdx(-1);
			offRecommendHandler();
		}
		if (e.key === 'Enter') {
			recLength > 0 && focusIdx >= 0 && setSearchValue(recWord[focusIdx]['sickNm']);
		}
	};
  1. keyDown이벤트가 발생하면 위의 함수가 실행된다.
  2. 누른 키가 ⬇️라면 받아온 데이터의 길이(recLength)가 0보다 많다면 실행된다.
    recLength > 0 && 조건문

최대 추천 검색어 정하기

추천 검색어가 많이 있더라도 7개까지만 보여주기로 했다. maxList = 7

그래서 recLength < maxList로 추천 검색어가 7개 보다 적을 때, 많을 때 2가지 경우를 대비했다.


마지막 추천 검색어에서 내려가면

마지막에서 내려간다면 다시 첫번째로 , 맨위에서 올라간다면 마지막으로 보내줘야 한다.

마지막에서 내려갈 경우

setFocusIdx((prev) => (prev + 1) % recLength) 나머지 연산자를 통해 설정한 수를 넘을 시 0이 된다.

맨위에서 올라갈 경우

setFocusIdx((prev) => (prev - 1 + recLength) % recLength) 설정한 수 만큼 더하고 나머지 연산자를 이용하면 -1일 경우 마지막 인덱스 숫자가 된다.

ex) (-1 + 7) % 7 = 6


원하는 추천 검색어

원하는 추천 검색어 부분에서 enter를 누르면 추천검색어가 있는지, focusIdx가 -1보다 큰지 확인후 추천검색어의 focusIdx번째를 Input value로 업데이트 한다.

if (e.key === 'Enter') {
	recLength > 0 && focusIdx > -1 && setSearchValue(recWord[focusIdx]['sickNm']);
}

post-custom-banner

0개의 댓글