聊一個複用元件中使用debounce時遇到的問題

陟上晴明發表於2023-02-14

今天我中遇到了一個這樣的場景,發現觸發複用的自定義元件中新增了防抖的函式,發現只執行了一次,並沒有如預期的那樣每個元件內的函式都執行一次。

一開始以為是沒有同步賦值,檢查了一下沒問題,才把關注點轉移到 debounce 上面。移除防抖之後果然解決問題了,但防抖又不能去去掉。

所以查了一下相關的問題,發現是因為多個元件例項是共享同一個預置防抖的函式,並不是相互獨立的。

一直以來都是直接如 Vue 檔案中演示的這樣來寫的,加上請求介面就會是下面這樣:

import debounce from "lodash.debounce";
import { remoteSearchAPI } from 'xxxx';

export default {
    // ...
    methods: {
        remoteMethod: debounce(function (value = "") {
            const params = {
                keywords: value,
            };
            this.fetching = true;
            remoteSearchAPI(params)
                .then((res) => {
                    // ...
                })
                .finally(() => {
                    this.fetching = false;
                });
        }, 350, { maxWait: 1000 }),
    },
};

這樣寫的話就會有一個問題:

這種方法對於被重用的元件來說是有問題的,因為這個預置防抖的函式是 有狀態的:它在執行時維護著一個內部狀態。如果多個元件例項都共享這同一個預置防抖的函式,那麼它們之間將會互相影響。
響應式基礎 | Vue.js

那麼如何解決這個問題呢?

Vue的檔案中也給出了相應的解決方案。

要保持每個元件例項的防抖函式都彼此獨立,我們可以改為在 created 生命週期鉤子中建立這個預置防抖的函式:
export default {
  created() {
    // 每個例項都有了自己的預置防抖的處理函式
    this.debouncedClick = _.debounce(this.click, 500)
  },
  unmounted() {
    // 最好是在元件解除安裝時
    // 清除掉防抖計時器
    this.debouncedClick.cancel()
  },
  methods: {
    click() {
      // ... 對點選的響應 ...
    }
  }
}

參考資源

vue 踩坑小記 - 如何正確的使用 debounce
#有狀態方法 響應式基礎 | Vue.js

本文參與了SegmentFault 思否寫作挑戰賽,歡迎正在閱讀的你也加入。

相關文章