React Input 防抖及處理中文(注音、拼音)

輸入防抖

防抖(Debounce)指的是在最後一次觸發 d 秒後執行函數,用意是避免過於頻繁的觸發函數。比較常見的運用情景是輸入提示(autocomplete)

防抖最常和節流一起被提起,一個簡單的圖片解釋防抖和節流之間的區別:

a2c81b50 8787 11eb ab90 d9ae814b240d React Input 防抖及處理中文(注音、拼音)
圖片來源: https://vue3js.cn/interview/JavaScript/debounce_throttle.html

基本寫法如下:

const debounce = (fn, delay) => {
    let timer = null;
    return function () {
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(fn, delay);
    };
  }

中文輸入處理

使用情景

一般來說,我們會用 onChange 來獲取當前輸入框的文字:

const handleChange = (e) => {
  console.log(e.target.value);
};
// ..
<input onChange={handleChange} />

當我們將輸入的內容在控制台輸出時就會發現注音的部分也被記錄下來了:

image 14 React Input 防抖及處理中文(注音、拼音)

如果今天我們只需要獲取最後輸入完畢的值那不會有太大的問題,但如果今天我們要根據輸入的內容去做關聯詞的搜索或者呼叫關鍵字搜索結果的 API …等那就會很耗效能而且可能會獲取到我們並不需要的結果。

解決辦法

這時候我們就可以用到 composition Event,composition Event 由 compositionStart, compositionUpdate 和 compositionEnd 三個事件組成。

  • compositionStart: 在開始輸入組合字(ex: 注音, 拼音)時執行一次。
  • compositionUpdate:類似 onChange,但會在 onChange 之前觸發,記錄每一次輸入的值。
  • compositionEnd: 在組合字結束(ex: Enter, Space)或輸入特殊符號、英文全形時會執行一次。
image 17 React Input 防抖及處理中文(注音、拼音)

寫法很簡單,只需要在 input 框上面加上 onCompositionStart, onCompositionEnd, onCompositionUpdate 來做處理就好。

export default function App() {
  const handleChange = (e) => {
    console.log("onChange", e.target.value);
  };

  const onStart = (e) => {
    console.log("onCompositionStart", e.target.value);
  };

  const onEnd = (e) => {
    console.log("onCompositionEnd", e.target.value);
  };

  const onUpdate = (e) => {
    console.log("onCompositionUpdate", e.target.value);
  };

  return (
    <div className="App">
      <input
        onChange={handleChange}
        onCompositionStart={onStart}
        onCompositionEnd={onEnd}
        onCompositionUpdate={onUpdate}
      />
    </div>
  );
}

大部分情況下我只會用到 onCompositionEnd 搭配 axios 實時請求數據來實現 autocomplete 的效果。

但需要注意的是因為 onCompositionEnd 處理的是組合結果(這邊以注音來舉例),所以單單只用它來呼叫搜索的函數是不夠的,可以配合 onChange 來處理剩餘的非組合文字(這邊代指英文字母)部分。

根據上述的情況,我們可以給定一個值 isOnComposition,用於判斷當前輸入的內容是否為組合字

const [isOnComposition, setIsOnComposition] = useState(false);

// ...

const onChange = (e) => {
  if (!isOnComposition && e.target.value) {
    console.log('onChange', e.target.value);
  }
}

const handleComposition = (e) => {
  if (e.type === 'compositionend') {
    let isOnComposition = false;
    setIsOnComposition(isOnComposition);

    if (!isOnComposition && e.target.value) {
      console.log('compositionend', e.target.value);
    }
  } else {
    setIsOnComposition(true);
  }
}

// ...

<input
  onChange={onChange}
  onCompositionStart={handleComposition}
  onCompositionUpdate={handleComposition}
  onCompositionEnd={handleComposition}
/>

如此一來就能輕鬆地獲取輸入的中文字及英文字母,不會拿到注音、拼音…等組合中的字符。

image 18 React Input 防抖及處理中文(注音、拼音)

我將這個範例放在了 CodeSandbox,有興趣可以嘗試一下:

0 0 評分數
Article Rating
訂閱
通知
guest

0 Comments
在線反饋
查看所有評論