[英]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 調用。 如何在fetchData
的debounce
中傳遞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 不會有任何區別。
請閱讀這篇文章以獲取缺少依賴項警告
我從不喜歡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.