繁体   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