Skip to main content

Change event fires extra times before IME composition ends

Enhanced Input Component

import { useRef, useState, forwardRef, InputHTMLAttributes } from 'react';

export const InputIME = forwardRef<HTMLInputElement, InputHTMLAttributes<HTMLInputElement>>((props, ref) => {
const { onChange, ...otherProps } = props;

// log if on composition
const onComposition = useRef(false);
// temp input
const [inputValue, setInputValue] = useState('');

const _onChange = (event) => {
setInputValue(event.target.value);

// IME method start
if (event.type === 'compositionstart') {
onComposition.current = true;
return;
}

// IME method end
if (event.type === 'compositionend') {
onComposition.current = false;
}

// handle parent onChange
if (!onComposition.current) {
onChange(event);
}
};

return <input {...otherProps} ref={ref} value={inputValue} onChange={_onChange} onCompositionEnd={_onChange} onCompositionStart={_onChange} />;
});

InputIME.displayName = 'InputIME';

related issue: https://github.com/facebook/react/issues/3926