如何在React.js中执行debounce ?

我想撤消handleOnChange。

我尝试debounce(这。handleOnChange, 200)但它不起作用。

function debounce(fn, delay) {
  var timer = null;
  return function() {
    var context = this,
      args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function() {
      fn.apply(context, args);
    }, delay);
  };
}

var SearchBox = React.createClass({
  render: function() {
    return <input type="search" name="p" onChange={this.handleOnChange} />;
  },

  handleOnChange: function(event) {
    // make ajax call
  }
});

当前回答

如果你不喜欢添加lodash或任何其他包:

import React, { useState, useRef } from "react";

function DebouncedInput() {
  const [isRefetching, setIsRefetching] = useState(false);
  const [searchTerm, setSearchTerm] = useState("");
  const previousSearchTermRef = useRef("");

  function setDebouncedSearchTerm(value) {
    setIsRefetching(true);
    setSearchTerm(value);
    previousSearchTermRef.current = value;
    setTimeout(async () => {
      if (previousSearchTermRef.current === value) {
        try {
          // await refetch();
        } finally {
          setIsRefetching(false);
        }
      }
    }, 500);
  }

  return (
    <input
      value={searchTerm}
      onChange={(event) => setDebouncedSearchTerm(event.target.value)}
    />
  );
}

其他回答

扩展useState钩子

import { useState } from "react";
import _ from "underscore"
export const useDebouncedState = (initialState, durationInMs = 500) => {
    const [internalState, setInternalState] = useState(initialState);
    const debouncedFunction = _.debounce(setInternalState, durationInMs);
    return [internalState, debouncedFunction];
};
export default useDebouncedState;

使用钩

import useDebouncedState from "../hooks/useDebouncedState"
//...
const [usernameFilter, setUsernameFilter] = useDebouncedState("")
//...
<input id="username" type="text" onChange={e => setUsernameFilter(e.target.value)}></input>

https://trippingoncode.com/react-debounce-hook/

避免使用event.persist()——你想让React回收合成事件。我认为无论你使用类还是钩子,最干净的方法是将回调函数分成两部分:

没有deboundation的回调 只使用您需要的事件片段调用已撤销的函数(这样合成的事件就可以循环使用)

handleMouseOver = throttle(target => {
  console.log(target);
}, 1000);

onMouseOver = e => {
  this.handleMouseOver(e.target);
};

<div onMouseOver={this.onMouseOver} />

功能

const handleMouseOver = useRef(throttle(target => {
  console.log(target);
}, 1000));

function onMouseOver(e) {
  handleMouseOver.current(e.target);
}

<div onMouseOver={this.onMouseOver} />

注意,如果你的handleMouseOver函数从组件中使用状态,你应该使用usemo而不是useRef,并将它们作为依赖项传递,否则你将使用过时的数据(当然不适用于类)。

简单有效 https://www.npmjs.com/package/use-debounce use-debounce

import { useDebouncedCallback } from 'use-debounce';

function Input({ defaultValue }) {
  const [value, setValue] = useState(defaultValue);
  const debounced = useDebouncedCallback(
    (value) => {
      setValue(value);
    },
    // delay
    1000
  );

  return (
    <div>
      <input defaultValue={defaultValue} onChange={(e) => debounced(e.target.value)} />
      <p>Debounced value: {value}</p>
    </div>
  );
}

您可以使用Lodash debounce https://lodash.com/docs/4.17.5#debounce方法。它简单有效。

import * as lodash from lodash;

const update = (input) => {
    // Update the input here.
    console.log(`Input ${input}`);     
}

const debounceHandleUpdate = lodash.debounce((input) => update(input), 200, {maxWait: 200});

doHandleChange() {
   debounceHandleUpdate(input);
}

您还可以使用下面的方法取消debounce方法。

this.debounceHandleUpdate.cancel();

希望对你有所帮助。干杯! !

/**
 * Returns a function with the same signature of input `callback` (but without an output) that if called, smartly
 * executes the `callback` in a debounced way.<br>
 * There is no `delay` (to execute the `callback`) in the self-delayed tries (try = calling debounced callback). It
 * will defer **only** subsequent tries (that are earlier than a minimum timeout (`delay` ms) after the latest
 * execution). It also **cancels stale tries** (that have been obsoleted because of creation of newer tries during the
 * same timeout).<br>
 * The timeout won't be expanded! So **the subsequent execution won't be deferred more than `delay`**, at all.
 * @param {Function} callback
 * @param {number} [delay=167] Defaults to `167` that is equal to "10 frames at 60 Hz" (`10 * (1000 / 60) ~= 167 ms`)
 * @return {Function}
 */
export function smartDebounce (callback, delay = 167) {
  let minNextExecTime = 0
  let timeoutId

  function debounced (...args) {
    const now = new Date().getTime()
    if (now > minNextExecTime) { // execute immediately
      minNextExecTime = now + delay // there would be at least `delay` ms between ...
      callback.apply(this, args) // ... two consecutive executions
      return
    }
    // schedule the execution:
    clearTimeout(timeoutId) // unset possible previous scheduling
    timeoutId = setTimeout( // set new scheduling
      () => {
        minNextExecTime = now + delay // there would be at least `delay` ms between ...
        callback.apply(this, args) // ... two consecutive executions
      },
      minNextExecTime - now, // 0 <= timeout <= `delay` ... (`minNextExecTime` <= `now` + `delay`)
    )
  }

  debounced.clear = clearTimeout.bind(null, timeoutId)

  return debounced
}
/**
 * Like React's `useCallback`, but will {@link smartDebounce smartly debounce} future executions.
 * @param {Function} callback
 * @param {[]} deps
 * @param {number} [delay=167] - Defaults to `167` that is equal to "10 frames at 60 Hz" (`10 * (1000 / 60) ~= 167 ms`)
 */
export const useDebounced = (callback, deps, delay = 167) =>
  useMemo(() => smartDebounce(callback, delay), [...deps, delay])