简体   繁体   English

将参数传递给 function 回调

[英]Pass a argument to a function callback

I'm trying to use debounce in lodash to delay the onChange, see the code below.我正在尝试在 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} />;
}

In the beginning, I was tring to use searchValue in fetchData function but seems because of scope, it failed to read it, it was always empty though the state had been updated.一开始,我试图在 fetchData function 中使用searchValue但似乎是因为 scope,它未能读取它,尽管 Z9ED39E2EA931586B6A985A6942EF57EZ 已更新,但它始终为空。

As a result, I try to pass it in from the debounceLoadData but I don't know how I can do that as what in useCallback is a function invocation.结果,我尝试从debounceLoadData传递它,但我不知道该怎么做,因为 useCallback 是 function 调用。 How can I pass searchValue in fetchData inside debounce .如何在fetchDatadebounce中传递searchValue

lodash debounce takes in a function as the first argument. lodash debounce 将 function 作为第一个参数。 You can simply use fetchData as the function and pass on the searchValue to debounceLoadData which will then be passed to fetchData on invocation您可以简单地将fetchData用作 function 并将searchValue传递给debounceLoadData ,然后在调用时将其传递给fetchData

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

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

debounce actually returns a function, think of debounce as being implemented like debounce 实际上返回一个 function,认为 debounce 是这样实现的

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

So basically debounceLoadData is the returned function here and arguments passed to it ie..args are being then passed to original function fetchData like func.apply(context, args)所以基本上debounceLoadData是这里返回的 function 和arguments passed to it ie..args然后被传递给原始 function fetch.argsData like func.apply(context, args)

Also debounceLoadData is created only once as the callback dependency is [] , you whether you pass it to useEffect as a dependency of not will not make any difference.同样debounceLoadData仅创建一次,因为回调依赖项是[] ,您是否将它作为 not 的依赖项传递给 useEffect 不会有任何区别。

Please read this post for missing dependency warning请阅读这篇文章以获取缺少依赖项警告

How to fix missing dependency warning when using useEffect React Hook? 使用 useEffect React Hook 时如何修复缺少的依赖警告?

I never like useCallback , it's quite a confusing hook, and I always use useMemo instead since it totally covers what useCallback can do (but not the other way around).我从不喜欢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]);

  // ...
}

Yet for your case I don't think using lodash debounce is the best solution.然而,对于您的情况,我不认为使用 lodash debounce 是最好的解决方案。

There's a hidden risk that the final invocation of effect fetchData happens AFTER your component is unmounted.存在一个隐藏的风险,即在卸载组件之后最终调用效果fetchData And if fetchData contains some state mutation logic, that would raise an error of "Can't call setState (or forceUpdate) on an unmounted component."如果fetchData包含一些 state 突变逻辑,则会引发“无法在未安装的组件上调用 setState(或 forceUpdate)”的错误。 which is not destructive but not optimal either.这不是破坏性的,但也不是最优的。

I suggest manually debounce call using setTimeout/clearTimeout .我建议使用setTimeout/clearTimeout手动去抖动调用。 It's pretty simple:这很简单:

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

I think you are getting confused by the functional setState syntax.我认为您对功能性setState语法感到困惑。 Try this:尝试这个:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM