返回文章列表
·1 分钟阅读·

React 输入法 Input 优化

背景

中文输入法触发次数过多或经过状态库异步处理后输入法无法正常使用的问题

原理

使用 composition 事件检测输入法输入

实现

首先动手确认下 compositionStart,compositionEnd,onChange 三者的顺序关系

<input
  onCompositionStart={() => {
    console.log("start");
  }}
  onChange={() => {
    console.log("change");
  }}
  onCompositionEnd={() => {
    console.log("end");
  }}
/>

chrome

image.png

safari

image.png

firefox

image.png

可以看到,顺序都是 start、change、end

结果

  1. 支持受控
  2. 无需进行浏览器判断,目前浏览器行为均一致
import { Input, InputProps } from "antd";
import { useRef, useState, forwardRef, useEffect } from "react";

/**
 * https://github.com/facebook/react/issues/3926#issuecomment-1200414788
 */
export const InputIME = forwardRef<any, InputProps>((props, ref) => {
  const { onChange, value, ...otherProps } = props;

  const [inputValue, setInputValue] = useState("");
  useEffect(() => {
    setInputValue(value as string);
  }, [value]);

  const onComposition = useRef(false);

  return (
    <Input
      // 其他默认值
      placeholder="请输入文本"
      autoComplete="off"
      {...otherProps}
      ref={ref}
      value={inputValue}
      onCompositionStart={() => {
        onComposition.current = true;
      }}
      onChange={(e) => {
        if (onComposition.current) {
          setInputValue(e.target.value);
        } else {
          onChange?.(e);
        }
      }}
      onCompositionEnd={(e) => {
        onComposition.current = false;
        onChange?.(e);
      }}
    />
  );
});

参考

  1. https://github.com/facebook/react/issues/3926#issuecomment-1200414788
  2. personal-blog/开发遇到的小问题合集/解决使用输入法输入在 React input 框中的问题.md at master · Jacky-Summer/personal-blog
  3. react-composition-input/src/inputfield.js at master · LeoEatle/react-composition-input