enter를 치면 input창이 클릭되도록 하는 함수를 만들었다.
keyup될 때 구현했는데 영어는 괜찮은데 자꾸 한글이 씹하는(?) 현상이 발생했다.
	const handleKeyUp = (e: KeyboardEvent<HTMLTextAreaElement>) => {
		if (textareaRef.current) {
			const maxHeight = 4 * 22; // 최대 4줄, 줄당 22px
			if (e.key === 'Enter') {
				e.preventDefault();
				if (e.ctrlKey) {
					if (textareaRef.current.scrollHeight < maxHeight) {
						const start = textareaRef.current.selectionStart;
						const end = textareaRef.current.selectionEnd;
						const value = textareaRef.current.value;
						const newValue = value.substring(0, start) + '\n' + value.substring(end);
						setContent(newValue);
						textareaRef.current.selectionStart = textareaRef.current.selectionEnd = start + 1;
					}
				} else {
					handleSendMessageButton();
				}
			}
		}
	};
<button
				className={bot-btn-send ${isOpenBottomMenu ? 'active' : ''}}
				onClick={handleSendMessageButton}>
				<IoSend className="send-svg" />
			</button>
알고보니 버튼이 두번 클릭되는 문제였다.
그럼 왜 영어는 괜찮은데 한글은 두번 클릭되는 현상이 발생할까?
바로 IME(입력기)가 작동하는 방식과 관련이 있다는 것!!
IME란 Input Method Editor로, 사용자가 여러 개의 키 입력을 통해 문자를 입력할 수 있도록 도와주는 소프트웨어이다.
이는 특히 한글, 중국어, 일본어와 같은 언어를 입력할 때 유용! 이러한 언어는 단일 키 입력으로 완전한 문자를 표현할 수 없으므로, IME는 여러 키 입력을 조합하여 최종 문자를 생성할 수 있다.
영어 입력의 경우, 각 키 입력이 즉시 처리되지만, 한국어 입력의 경우 IME가 여러 키 입력을 조합하여 하나의 글자를 완성한다. 이 과정에서 이벤트가 여러 번 발생할 수 있으며, 특히 조합이 완료되지 않은 상태에서 Enter 키를 누르면 onKeyDown과 onKeyUp 이벤트가 예상치 않게 처리될 수 있다는 것!
이에 대한 해결책으로
onCompositionStart와 onCompositionEnd를 사용하여 IME 입력이 시작하는 시점 끝나는 시점을 보고 끝났을 때만 handleSendMessageButton함수가 실행되게 변경해주었다.
	const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
		const platform = getPlatform();
		const isCtrlOrCmd = platform === 'Mac' ? e.metaKey : e.ctrlKey;
		if (textareaRef.current) {
			if (e.key === 'Enter' && !isComposing) {
				if (isCtrlOrCmd) {
					const maxHeight = 4 * 22; // 최대 4줄, 줄당 22px
					if (textareaRef.current.scrollHeight < maxHeight) {
						const start = textareaRef.current.selectionStart;
						const end = textareaRef.current.selectionEnd;
						const value = textareaRef.current.value;
						const newValue = value.substring(0, start) + '\n' + value.substring(end);
						setContent(newValue);
						textareaRef.current.selectionStart = textareaRef.current.selectionEnd = start + 1;
					}
				} else {
					e.preventDefault();
					handleSendMessageButton();
				}
			}
		}
	};
    
    	const handleCompositionStart = () => {
		setIsComposing(true);
	};
	const handleCompositionEnd = () => {
		setIsComposing(false);
	};
				<textarea
					ref={textareaRef}
					className="bot-textarea"
					onChange={handleInputChange}
					onKeyDown={handleKeyDown}
					onCompositionStart={handleCompositionStart}
					onCompositionEnd={handleCompositionEnd}
					value={content}
					placeholder="Send a message.."
					rows={1}
					onInput={adjustTextareaHeight}
				/>
아주 잘 동작하는 것을 확인해볼 수 있었다!
'Problem&Solution' 카테고리의 다른 글
| 로컬state를 만들어 서버 부하 줄이기 (0) | 2024.07.17 | 
|---|---|
| Typescript 인덱싱 에러 (0) | 2024.07.15 | 
| react-query, retetchOnWindowFocus (0) | 2024.06.26 | 
| react 버그 해결 (1) | 2024.06.10 | 
| react hook의 호출 규칙 (0) | 2024.05.08 |