본문 바로가기

카테고리 없음

[React] 자동완성 기능 구현 중 한글이 두번 써지는 현상 해결하기

 

 

 

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;

수정된 코드 설명

  1. IME 상태 추적: isComposing 상태를 추가해, compositionstart 이벤트가 발생하면 true로 설정하고, compositionend 이벤트가 발생하면 false로 설정합니다.
  2. 자동완성 제어: Tab 키 이벤트 처리 시 isComposing이 false일 때만 자동완성 처리가 실행되도록 조건을 추가했습니다.