【问题标题】:Debounce in React es6React es6 中的去抖动
【发布时间】:2020-11-01 10:23:59
【问题描述】:

我的一个页面中有一个搜索输入,我正在努力确保如果用户输入速度过快,它不会在一秒钟内发出 10 个请求。

似乎去抖动是要走的路。我已经阅读了多篇博客文章和 SO 问题。我正在尝试使用 lodash 的 debounce。我一定是做错了什么,因为我的所有调用都通过了,就在稍后。

这是我的组件代码:

const Partners = (props: any) => {
  const [query, setQuery] = useState("");
  const { partners, totalPages, currentPage } = props.partnersList;

  useEffect(() => {
    props.getPartners();
  }, []);

  useEffect(() => debounce(() => props.getPartners(query), 10000), [query]);

  const handleQueryChange = (e: any) => {
    setQuery(e.target.value);
  };

  const handlePageChange = (e: React.ChangeEvent<unknown>, value: number) => {
    props.getPartners(query, value);
  };

  return (
    <React.Fragment>
      <Sidebar />
      <MainContent className="iamSearchPartners">
        <h1>Partners</h1>
        <TextField
          className="iamSearchPartners__search_input"
          variant="outlined"
          size="small"
          onChange={handleQueryChange}
          value={query}
        />
        <PartnersList partners={partners} />
        {totalPages > 1 && (
          <Pagination
            currentPage={currentPage || 1}
            totalPages={totalPages}
            handlePageChange={handlePageChange}
          />
        )}{" "}
      </MainContent>
    </React.Fragment>
  );
};

如您所见,我有一个 useEffect 监听查询的变化。

【问题讨论】:

  • 这是迄今为止我为 debounce 事件找到的最好的库之一:github.com/xnimorz/use-debounce 看看。还有一个 defaultValue={curretState} 将显着提高你的表现,这是一个加号。

标签: javascript reactjs ecmascript-6 debouncing


【解决方案1】:

debounce 创建作为参数传递的函数的去抖动版本。在这种特定情况下,在 useEffect 中调用它会在每次渲染时创建一个新的去抖动版本的函数。

为了缓解这种情况,可以在渲染函数之外创建去抖动版本,因此不会在每次渲染时重新创建。

const myDebouncedFunction = debounce((handler, query) => handler(query), 10000);

const Partners = (props: any) => {
  // omitted ...
  useEffect(() => {
    myDebouncedFunction(props.getPartners, query);
  }, [query]);
  // omitted ...

useMemo 或将其放入 useState 也可以。

另一件事:useEffect 只调用了返回的去抖动版本,因为它是一个没有大括号的箭头函数,使其返回评估结果。 useEffect 利用 return 的功能成为某种“取消订阅”处理程序 see React docs about "Effects with cleanup"。所以每当query 改变(第二次之后),效果就是调用函数。每次查询更改都应调用上述版本。

就个人而言,我会尝试在handleQueryChange 而不是useEffect 中处理函数的去抖动版本的调用,以使“何时应该发生”更清楚。

【讨论】:

  • 从组件外部调用函数使其工作。我还从 handleQueryChange 中调用了 debounced 函数。这样就更清楚了。非常感谢!
【解决方案2】:

老实说,我最终还是手动操作。查看debouncing and throttling 之间的区别。我认为您想限制请求。如果你去抖动,在计时器结束之前什么都不会发生。

如果您想像示例中那样等待 10 秒,如果用户至少每 10 秒键入一次,直到最后一次键入后 10 秒,什么都不会发生。与每 10 秒发出一次请求的限制相反。

这种方法是一种混合方法,因为我们确保最后一个仍然熄灭(就像去抖一样),并且节流可能不会这样做,但我们仍然会在用户输入时发送请求。

  const timer = useRef<number>(0);
  const lastEventSent = useRef(Date.now());

  useEffect(() => {
     if (Date.now() - lastEventSent.current < 500) {

     // The event was fired too recently, but we still want
     // to fire this event after the timeout if it is the last
     // one (500ms in this case).
      timer.current = setTimeout(() => {
          lastEventSent.current = Date.now();
          props.getPartners(query)
      }, 500);

     } else {

       // An event hasn't been fired for 500ms, lets fire the event
       props.getPartners(query)
       lastEventSent.current = Date.now();

       // And if the user was typing, there is probably a timer, lets clear that
       clearTimeout(timer.current);
     }
  
     // Cleanup the timer if there was one and this effect is reloaded.
     return () => clearTimeout(timer.current);

   }, [query]);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-16
    • 2022-01-13
    • 1970-01-01
    • 2017-05-03
    • 2020-04-28
    • 2016-07-17
    • 1970-01-01
    • 2018-09-18
    相关资源
    最近更新 更多