
input에 입력후 Enter를 눌렀을때 string 배열에 입력값을 push해서 보여지는 UI를 만들었다
영어를 입력했을땐 문제가 없었으나, 한글을 입력하고 엔터를 누르면 끝 글자만 떨어져나와 2개씩 string이 생성되는 문제가 발생하게 되었다
사실 늘 이런 컴포너는트는 mantine을 쓰든 뭘 쓰든 대부분 UI 라이브러리를 사용해서 가져다 쓰기만했었지 직접 만드는건 처음이게 이런 문제가 발생할 수 있다는걸 모르고 있었다
그래서 keyUp으로 뭔갈 해야해야하나? 지연을 줘서 늦게 input을 리셋 시켜야하나? 고민하다가 chatGPT한테 물어보니 원인을 알 수 있었다
<div className="w-full px-4 rounded border border-gray-300 text-sm min-h-[30px] py-2 placeholder:text-sm placeholder:text-gray-400">
{values.map((v, idx) => (
<span
key={`${v}-${idx}`}
className="px-2 py-[2px] inline-flex items-center bg-[#EFEFEF] rounded-full mr-1 mb-2"
>
<span className="text-sm">{v}</span>
<button type="button" className="w-4">
<XMarkIcon />
</button>
</span>
))}
<input
type="text"
placeholder={props.placeholder}
className="w-full outline-none"
value={inputValue}
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
e.preventDefault();
const value = e.currentTarget.value.trim();
if (value) {
setValues((prev) => [...prev, value]);
setInputValue("");
}
console.log(e.currentTarget.value);
}
}}
onChange={(e) => {
const value = e.target.value;
setInputValue(value);
}}
/>
</div>
기존에는 이렇게 작성 했고 GPT가 내놓은 답은 아래와 같다
function MultiSelect({ ...props }: IInputProps) {
const [inputValue, setInputValue] = useState<string>("");
const [values, setValues] = useState<string[]>([]);
const [isComposing, setIsComposing] = useState(false); // 한글 조합 상태 확인
return (
<div className="w-full px-4 rounded border border-gray-300 text-sm min-h-[30px] py-2 placeholder:text-sm placeholder:text-gray-400">
{values.map((v, idx) => (
<span
key={`${v}-${idx}`}
className="px-2 py-[2px] inline-flex items-center bg-[#EFEFEF] rounded-full mr-1 mb-2"
>
<span className="text-sm">{v}</span>
<button type="button" className="w-4">
<XMarkIcon />
</button>
</span>
))}
<input
type="text"
placeholder={props.placeholder}
className="w-full outline-none"
value={inputValue}
onCompositionStart={() => setIsComposing(true)}
onCompositionEnd={() => setIsComposing(false)}
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter" && !isComposing) {
e.preventDefault();
const value = e.currentTarget.value.trim();
if (value) {
setValues((prev) => [...prev, value]);
setInputValue(""); // 더 깔끔한 방식
}
}
}}
onChange={(e) => setInputValue(e.target.value)}
/>
</div>
);
}
conpositionstart, compositionend를 활용한 방법이다. 이런 이벤트도 지원해주는지 몰랐다 ^_ㅠ...
두 이벤트는 조합을 활용하는 언어들의 조합 시작과 끝을 추적해준다
- conpositionstart : 조합 시작, 조합중인 문자열을 알 수 있음
- conpositionend : 조합 끝. 조합이 끝난 문자열을 알 수 있음
왜 영어를 입력할때랑 한글을 입력할때랑 다를까?
영어는 키보드를 누를때마다 바로바로 문자 하나씩 입력되고 끝난다. 조합이란게 없는 언어라서 onKeyDown, onChange, onKeyUp 등 이벤트가 있는 그대로 단순하게 작동한다.
근데 영어와 달리 한글은 IME(입력기)를 통해 문자를 조합하는 툭수한 입력 방식이다. 이 과정은 브라우저가 처리하는게 아니라 운영체제의 IME가 중간에서 조합 상태를 관리해준다고 한다
그렇다보니, onKeyDown, onChange 이벤트 같은 경우 한글이 아직 조합중인데 발생할 수 있다. 우리는 문자열 1개가 조합 되어야하지 입력을 완료(?)했다고 볼 수 있다보니 이벤트 발동 타이밍이 불명확 해지는 것이다. Enter도 조합중에 누르면 확정 + 키다운이 동시에 발생할 수 있는 것이다.
그래서 "안녕" 입력후 Enter를 누를때 "안녕" 1개, "녕" 1개 2번 발생하는 과정을 보면
- 조합 도중 "안녕"이 value로 보이게 됨
- 그 상태에서 Enter 누르면
- 조합이 끝나기 전에 onKeyDown 실헹 -> "안녕"이 추가
- 이어서 조합이 확정되며 onKeyDown이 다시 한번 더 실행 -> "녕"만 따로 value로 들어와 또 추가됨
이렇게 되는 것이다
이게 다 조합중이다보니 키보드 관련 타이밍이 꼬이는것이다

아무튼, GPT가 제시해준 방법대로 고치니 이젠 2번 등록되는 이슈가 사라졌다
'Frontend' 카테고리의 다른 글
CRA 지원 종료. Vite로 마이그레이션 하기 (0) | 2025.05.20 |
---|---|
CRA 절대경로로 변경하는 법 (0) | 2025.05.19 |
[React] createPortal을 이용해서 Toast 컴포넌트 만들기 (0) | 2025.03.18 |
Github actions OIDC로 배포 자동화하기 (1) | 2025.01.24 |
[React] 우린 왜 state, function, effect 순으로 작성했는가 (2) | 2025.01.16 |
댓글