카테고리 없음
[React] 자동완성 기능 구현 중 한글이 두번 써지는 현상 해결하기
늘이
2024. 11. 7. 19:55
1. 문제 상황
- 영어 입력은 문제가 없었지만 한글 입력의 경우 문제 발생했습니다.
- 아래와 같이 입력중이던 마지막 문자가 추천키워드 뒤에 나온다는 것입니다.
2. 원인
- IME의 조합 상태: 한글 IME는 자음과 모음이 조합되는 과정에서 compositionstart, compositionupdate, compositionend 이벤트를 발생시킵니다. React에서 상태 업데이트가 이 조합 중간에 실행되면 한글 입력이 중단되거나 커서 위치가 예기치 않게 이동할 수 있습니다.
- React의 비동기 상태 업데이트: React의 setState는 비동기적으로 상태를 업데이트하므로, 한글 입력 상태에서 Tab 키로 자동완성 텍스트를 추가하려고 할 때 업데이트 순서나 타이밍이 IME 입력 처리와 충돌할 수 있습니다.
3. 해결 방법
IME 입력이 완료된 후에만 자동완성 처리를 하도록 하여 해결할 수 있습니다. 이를 위해 compositionstart와 compositionend 이벤트를 활용하여 IME 상태를 추적하고, Tab 키가 눌렸을 때 IME가 활성화된 상태인지 확인한 후, 필요할 경우 compositionend 이벤트를 강제로 호출하여 입력을 완료 상태로 전환합니다.
4. 수정된 코드
import React, { useState } from "react";
import menuList from "./MenuList.js";
import "./App.css";
function App() {
const [menuName, setMenuName] = useState("");
const [filteredMenus, setFilteredMenus] = useState([]); // 메뉴명 필터링 결과(=자동 완성 리스트)
const [suggestion, setSuggestion] = useState(""); // 메뉴명 자동완성 제안 텍스트
const [isComposing, setIsComposing] = useState(false); // IME 활성 상태 추적
// 메뉴명 필드 입력 시 필터링 및 자동완성 제안 텍스트 설정
const handleMenuNameChange = (e) => {
const input = e.target.value;
console.log("메뉴명 입력:", input);
setMenuName(input); // 입력한 내용을 menuName으로 업데이트
if (input) {
const matchedMenu = menuList.find((menu) => menu.startsWith(input));
setFilteredMenus(menuList.filter((menu) => menu.includes(input)));
setSuggestion(matchedMenu ? matchedMenu.slice(input.length) : ""); // 제안 텍스트 설정
} else {
setFilteredMenus([]);
setSuggestion("");
}
};
// IME 입력 시작
const handleCompositionStart = () => {
setIsComposing(true);
};
// IME 입력 종료
const handleCompositionEnd = () => {
setIsComposing(false);
};
// 메뉴명 입력 필드에서 Tab 키 누를 때 추천 단어로 자동 완성
const handleMenuNameKeyDown = (e) => {
if (e.key === "Tab" && suggestion && !isComposing) {
e.preventDefault(); // 기본 탭 동작 막기
setMenuName(menuName + suggestion); // 메뉴명에 추천 단어 추가
setSuggestion(""); // 추천 단어 초기화
setFilteredMenus([]); // 추천 목록 초기화
}
};
return (
<div className="menu-section">
<label htmlFor="menuName">메뉴명</label>
<div className="input-with-suggestion">
<input
type="text"
id="menuName"
value={menuName}
onChange={(e) => {
handleMenuNameChange(e);
e.target.style.setProperty("--input-length", e.target.value.length);
}}
onCompositionStart={handleCompositionStart} // IME 입력 시작
onCompositionEnd={handleCompositionEnd} // IME 입력 종료
onKeyDown={handleMenuNameKeyDown} // Tab 키 이벤트 추가
/>
{suggestion && (
<span className="suggestion">
{menuName}
<span className="suggestion-text">{suggestion}</span>
</span>
)}
</div>
</div>
);
}
export default App;
수정된 코드 설명
- IME 상태 추적: isComposing 상태를 추가해, compositionstart 이벤트가 발생하면 true로 설정하고, compositionend 이벤트가 발생하면 false로 설정합니다.
- 자동완성 제어: Tab 키 이벤트 처리 시 isComposing이 false일 때만 자동완성 처리가 실행되도록 조건을 추가했습니다.