Debounce & Throttle in React - 1


Posted by backas36 on 2022-04-05

之前很常忘記這兩個,常常記錯,更早之前是看到這兩個單字就直接跳過,因為感覺很艱深,一直到去年與同學一起做履歷作品的時候,因為面臨到一些技術問題,所以不得不開始了解 debounce 和 throttle。

所以對於學習到一個階段的同學,別害怕,終究會遇到的,因為已經開始擔任前端工程師的我,在未滿第三個月的現在也遇到了 T.T

Debounce

debounce 非常適合用在一些 autocomplete 的東西上,eg. search bar。
例如說當我們在 search bar input 輸入 debounce 時,如果沒有使用 debounce 概念的話會變成是當鍵盤輸入
d => 打 api 搜尋
e => 第二次打 api 搜尋
b => 第三次 ...
o => 第四次
..
..

如果加入了 debounce 概念之後,我們可以變成這樣

<假設delay設置 300 毫秒>
d => 當輸入 d 時,300毫秒內如果沒有再輸入的話就會打第一次 api

(如果300毫秒內輸入...)
e => 輸入 e 時,重新計時,300毫秒內如果沒有再輸入的話就會打第二次 api

(如果300毫秒內輸入...)
b => 輸入 b 時,300毫秒內如果沒有再輸入的話就會打第三次 api

..
..

接下來我們可以看正常的 input 和 加入 debounce 概念的 input 在 react 該怎麼實作:

這是兩個 input dom,第一個是 default,第二個待會會加入 debounce 。

    //...
  return (
   <>
      <div>
        <input value={input} onChange={onInputChange} />
      </div>
      <div>
        <input value={inputDebounce} onChange={onInputDebounceChange} />
      </div>
    </>
  );

接下來看看 onInputChange 和 onInputDebounceChange 該怎麼實作:

input 的 input 綁定的 click 事件:

const onInputChange = (e) => {
    setInput(e.target.value);
    fetchData(e.target.value)
    console.log('fire onInputChange');
 };

inputDebounce 綁定的 click 事件以及需要用到的function:

const debounce = (fn, delay = 300) =>{
    let timer 
    return  (...args)=>{
    console.log(timer)

      if(timer){
        clearTimeout(timer)
      }
      timer = setTimeout(()=>{
        timer = null
        fn(...args)
      },delay)
    }
  }

const debounceHandler = useCallback(debounce(fetchData,3000),[])

const onInputDebounceChange = (e) => {
    setInputDebounce(e.target.value)
    debounceHandler(e.target.value)
  }

當 user click 之後觸發了 onInputDebounceChange => setInputDebounce 更改 inputDebounce 的狀態 => debounceHandler 帶著 e.target.value 執行了 debounce function,第一個參數是 setTimeout ,也就是時間到了之後要做什麼動作(fetchData),以及第二個參數 300 (如果沒有帶第二個參數就會是預設的 1000 毫秒)。

核心是在 debounce 那個 function,debounce 會接收剛剛介紹的那兩個 function,然後會先宣告一個 timer,這是因為執行完這個 function 之後會需要用到這個 timer (因為要重新計時),最後 debounce 會回傳一個 function:
這個 function 會先清掉上一次的 timer,並且開始重新計時 delay (300) 幾秒後執行 fn (fetchData)。

是不是有點類似 closure 概念,沒錯!就是 closure,之前也有介紹過 closure,可以參考之前我寫的 JavaScript 程式執行原理:Closure

完整的程式碼範例我會放在這裡,有需要的話可以參考:
https://stackblitz.com/edit/react-dqq5ht?file=src/App.js

第二篇我會介紹一下 Throttle。


#React #debounce #js







Related Posts

[Golang] slice 作為參數傳入 func 的注意事項

[Golang] slice 作為參數傳入 func 的注意事項

蔡比八寫後端(6) - TypeORM entity & column

蔡比八寫後端(6) - TypeORM entity & column

Day 71 - Major & Salary Datas Exploration

Day 71 - Major & Salary Datas Exploration


Comments