簡體   English   中英

將參數傳遞給 function 回調

[英]Pass a argument to a function callback

我正在嘗試在 lodash 中使用 debounce 來延遲 onChange,請參見下面的代碼。

import React, { useState, useEffect, useCallback } from "react";
import { TopBar } from "@shopify/polaris";
import { debounce } from "lodash";

function SearchBar() {
  const [searchValue, setSearchValue] = useState("");

  const handleSearchFieldChange = ((value:string) => {
    setSearchValue(value);
  });

  const debounceLoadData = useCallback(debounce({searchValue} => fetchData, 1000), []);

  useEffect(() => {
    debounceLoadData();
    console.log({searchValue})
  }, [searchValue]);

  function fetchData(value:string) {
    console.log("searchValue " + value);
  }

  const searchFieldMarkup = (
    <TopBar.SearchField
      onChange={handleSearchFieldChange}
      value={searchValue}
      placeholder="Search Value"
    />
  );

  return <TopBar searchField={searchFieldMarkup} />;
}

一開始,我試圖在 fetchData function 中使用searchValue但似乎是因為 scope,它未能讀取它,盡管 Z9ED39E2EA931586B6A985A6942EF57EZ 已更新,但它始終為空。

結果,我嘗試從debounceLoadData傳遞它,但我不知道該怎么做,因為 useCallback 是 function 調用。 如何在fetchDatadebounce中傳遞searchValue

lodash debounce 將 function 作為第一個參數。 您可以簡單地將fetchData用作 function 並將searchValue傳遞給debounceLoadData ,然后在調用時將其傳遞給fetchData

const debounceLoadData = useCallback(debounce(fetchData, 1000), []);

  useEffect(() => {
    debounceLoadData(searchValue);
    console.log({searchValue})
  }, [searchValue]);

debounce 實際上返回一個 function,認為 debounce 是這樣實現的

function debounce(func, wait) {
  let timeout
  return function(...args) {
    const context = this
    clearTimeout(timeout)
    timeout = setTimeout(() => func.apply(context, args), wait)
  }
}

所以基本上debounceLoadData是這里返回的 function 和arguments passed to it ie..args然后被傳遞給原始 function fetch.argsData like func.apply(context, args)

同樣debounceLoadData僅創建一次,因為回調依賴項是[] ,您是否將它作為 not 的依賴項傳遞給 useEffect 不會有任何區別。

請閱讀這篇文章以獲取缺少依賴項警告

使用 useEffect React Hook 時如何修復缺少的依賴警告?

我從不喜歡useCallback ,這是一個非常令人困惑的鈎子,我總是使用useMemo代替,因為它完全涵蓋了useCallback可以做什么(但不是相反)。

function SearchBar() {
  const [searchValue, setSearchValue] = useState("");

  const handleSearchFieldChange = ((value:string) => {
    setSearchValue(value);
  });

  const debounceLoadData = useMemo(() => debounce(fetchData, 1000), []);
  /**
   * the equivalent of useCallback should be:
   *
   * const debounceLoadData = useCallback(debounce(fetchData, 1000), []);
   * 
   * But I really advice against it!
   * There's unnecessary function invocation compared to useMemo.
   */


  useEffect(() => {
    debounceLoadData(searchValue);  // <- you should pass in arg
    console.log({searchValue})
  }, [searchValue]);

  // ...
}

然而,對於您的情況,我不認為使用 lodash debounce 是最好的解決方案。

存在一個隱藏的風險,即在卸載組件之后最終調用效果fetchData 如果fetchData包含一些 state 突變邏輯,則會引發“無法在未安裝的組件上調用 setState(或 forceUpdate)”的錯誤。 這不是破壞性的,但也不是最優的。

我建議使用setTimeout/clearTimeout手動去抖動調用。 這很簡單:

useEffect(() => {
  const timeoutId = setTimeout(() => fetchData(searchValue), 1000)
  return () => clearTimeout(timeoutId)
}, [searchValue])

我認為您對功能性setState語法感到困惑。 嘗試這個:

const debounceLoadData = useCallback(() => debounce(() => fetchData(searchValue), 1000), []);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM