<aside> 💡 React에선 onKeyDownonKeyPressonChange(value 변경됨) → onKeyUp(value 변경됨) 이벤트 순서대로 핸들러가 호출된다. 일반 자바스크립트에서 change 이벤트는 value 속성이 변경되고 포커스를 해제해야 호출되지만, React에선 Input 이벤트처럼 value 속성 값이 변경될 때마다 호출된다.

</aside>

text 타입 일 때


onKeyDown onKeyPress 이벤트는 핸들러 안에서 e.preventDefault() 메서드를 호출하면 입력을 막을 수 있다. 하지만 한글을 포함한 CJK 문자(조합 문자)는 메서드를 호출해도 그대로 입력된다. 이 방법은 숫자나 영어 입력을 막을때만 유효하다. 아래 방법으로 해결할 수 있다.

export default function App() {
  const OnKeyDown = (e) => {
    e.preventDefault();
  };

  return (
    <div className="App">
      <h1>Only allow numbers in input</h1>
      <label>
        <span className="label">Text Type</span>
        <input type="text" onKeyDown={OnKeyDown} />
      </label>
    </div>
  );
}

방법 1 — value 교체 (uncontrolled)

<aside> 💡 정규식에서 \\d 메타 문자는 10진수([0-9] 와 동일), \\D는 10진수가 아닌 문자를 가리킨다

</aside>

onChange 이벤트가 발생하면 핸들러 안에서 숫자가 아닌 모든 value를 빈문자열로 대체한다. onKeyDown 이벤트는 value 속성이 바뀌기 전에 호출하므로 사용할 수 없고, onKeyUp 이벤트는 한글(CJK 문자)이 지워지는 과정을 육안으로 확인 할 수 있어서 UX에 좋지 않다. 따라서 onChange 이벤트를 사용한다.

const onChange = (e) => {
  // onChange 이벤트가 발생할 때마다 10진수가 아닌 문자를 모두 빈문자열로 대체
  // 방향키, 백스페이스 등도 잘 작동한다
  e.target.value = e.target.value.replaceAll(/\\D/g, "");
};

return (
  <label>
    <span className="label">Text Type</span>
    <input type="text" onChange={onChange} />
  </label>
);

방법 2 — 숫자일때만 상태 변경 (controlled)

onChange 이벤트가 발생해서 핸들러를 호출하는 시점엔 value 속성 값이 이미 바뀌어 있는 상태다. 예를들어 현재 Input에 88이 입력된 상태에서 a를 입력하면 핸들러 안에서 e.target.value88a가 된다.

정규식을 이용해서 e.target.value에 10진수 문자만 있을때 상태를 변경하면 ➊숫자만 허용하면서 ➋불필요한 렌더링을 방지할 수 있다. value 속성 값이 변경된 후 onChange 이벤트를 제어하므로 방향키나 백스페이스 등은 모두 정상적으로 이용할 수 있다.

const [textValue, setTextValue] = useState("");

const onChange = (e) => {
  // '88'.match(/\\D/g) -> null
  // !'88'.match(/\\D/g) -> true -> 조건 통과 후 상태 변경
  // '88a'.match(/\\D/g) -> ['a']
  // !'88a'.match(/\\D/g) -> false -> 조건 통과 못해서 상태 변경 안함
  if (!e.target.value.match(/\\D/g)) setTextValue(e.target.value);
};

return (
  <label>
    <span className="label">Text Type</span>
    <input type="text" value={textValue} onChange={onChange} />
  </label>
);

number 타입일 때


<input type="number" />일 땐 기본적으로 숫자만 입력할 수 있다. 하지만 CJK 문자는 아래 이미지처럼 입력 필드에 그대로 표시되는 문제가 있다. number 타입 Input에서 CJK 문자 입력 방지는 생각보다 까다롭다.

CJK 조합 문자에서 조합을 시작했거나 조합중일 때 밑줄이 나타난다

CJK 조합 문자에서 조합을 시작했거나 조합중일 때 밑줄이 나타난다

일단 CJK 문자 입력은 onChange onKeyPress 이벤트가 감지하지 못한다. 즉, 한글을 입력해도 핸들러가 호출되지 않는다. 대신 onKeyDown onKeyUp 이벤트를 사용해야 CJK 문자 입력을 감지할 수 있다.

방법 1 — value 교체 (uncontrolled)