690 Stimmen

Wie kann ich ein Debounce durchführen?

Wie führen Sie eine Verzögerung in React durch?

Ich möchte die Funktion handleOnChange verzögern.

Ich habe es mit debounce(this.handleOnChange, 200) versucht, aber es funktioniert nicht.

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 ;
  },

  handleOnChange: function(event) {
    // Führen Sie Ajax-Aufruf durch
  }
});

2voto

Francisco Hanna Punkte 1147

Ich bin heute auf dieses Problem gestoßen und habe es mit setTimeout und clearTimeout gelöst.

Ich werde ein Beispiel geben, das Sie anpassen könnten:

import React, { Component } from 'react'

const DEBOUNCE_TIME = 500

class PlacesAutocomplete extends Component {
  debounceTimer = null;

  onChangeHandler = (event) => {
    // Letzten registrierten Timer für die Funktion löschen
    clearTimeout(this.debounceTimer);

    // Einen neuen Timer setzen
    this.debounceTimer = setTimeout(
      // Die Rückruffunktion binden, um den aktuellen Eingabewert als Argument zu übergeben
      this.getSuggestions.bind(null, event.target.value),
      DEBOUNCE_TIME
    )
  }

  // Die Funktion, die verzögert wird
  getSuggestions = (searchTerm) => {
    console.log(searchTerm)
  }

  render() {
    return (

    )
  }
}

export default PlacesAutocomplete

Sie könnten es auch in eine eigene Funktionkomponente refaktorisieren:

import React from 'react'

function DebouncedInput({ debounceTime, callback}) {
  let debounceTimer = null
  return (
     {
      clearTimeout(debounceTimer);

      debounceTimer = setTimeout(
        callback.bind(null, event.target.value),
        debounceTime
      )
    }} />
  )
}

export default DebouncedInput

Und verwenden Sie es wie folgt:

import React, { Component } from 'react'
import DebouncedInput from '../DebouncedInput';

class PlacesAutocomplete extends Component {
  debounceTimer = null;

  getSuggestions = (searchTerm) => {
    console.log(searchTerm)
  }

  render() {
    return (

    )
  }
}

export default PlacesAutocomplete

2voto

user1079877 Punkte 8419

Diese Lösung benötigt keine zusätzlichen Bibliotheken und startet auch, wenn der Benutzer die Taste Enter drückt:

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

const [search, setSearch] = useState('');
const [searchFor, setSearchFor] = useState(search);

useEffect(() => {
    console.log("Suche:", searchFor);
}, [searchFor]);

const fireChange = event => {
    const { keyCode } = event;
    if (keyCode === 13) {
        event.preventDefault();
        setSearchFor(search);
    }
}

const changeSearch = event => {
    const { value } = event.target;
    setSearch(value);
    debounceSetSearchFor(value);
};

const debounceSetSearchFor = useCallback(debounce(function(value) {
    setSearchFor(value);
}, 250), []);

Und das Eingabefeld könnte so aussehen:

2voto

Siva Kannan Punkte 1968

Einfach und effektiv: Verwenden Sie use-debounce

import { useDebouncedCallback } from 'use-debounce';

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

  return (

       debounced(e.target.value)} />
      Verzögerte Wert: {value}

  );
}

1voto

Mir-Ismaili Punkte 10534
/**
 * Gibt eine Funktion mit der gleichen Signatur wie die Eingabefunktion `callback` (aber ohne Ausgabe) zurück, die bei Aufruf auf kluge Weise
 * die `callback`-Funktion verzögert ausführt.
 * Es gibt kein `delay` (Zeitverzögerung für die Ausführung des `callback`) in den selbstverzögerten Versuchen (Versuch = Aufruf der verzögerten Callback-Funktion). 
 * Es verzögert **nur** nachfolgende Versuche (die vor einem Mindestzeitablauf (`delay` ms) nach der letzten Ausführung liegen). Es **verwirft auch veraltete Versuche** 
 * (die aufgrund der Erstellung neuerer Versuche während des gleichen Zeitablaufs obsolet geworden sind).
 * Die Verzögerung wird nicht erweitert! Also **die nachfolgende Ausführung wird niemals um mehr als `delay` verzögert**.
 * @param {Function} callback
 * @param {number} [delay=167] Standardmäßig auf `167` gesetzt, was "10 Frames bei 60 Hz" entspricht (`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) { // sofort ausführen
      minNextExecTime = now + delay // zwischen zwei aufeinander folgenden Ausführungen gibt es mindestens `delay` ms
      callback.apply(this, args) // ... zwei aufeinander folgenden Ausführungen
      return
    }
    // Ausführung planen:
    clearTimeout(timeoutId) // eventuelle vorherige Planung aufheben
    timeoutId = setTimeout( // neue Planung setzen
      () => {
        minNextExecTime = now + delay // zwischen zwei aufeinander folgenden Ausführungen gibt es mindestens `delay` ms
        callback.apply(this, args) // ... zwei aufeinander folgenden Ausführungen
      },
      minNextExecTime - now, // 0 <= Timeout <= `delay` ... (`minNextExecTime` <= `now` + `delay`)
    )
  }

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

  return debounced
}

/**
 * Ähnlich wie React's `useCallback`, jedoch werden zukünftige Ausführungen {@link smartDebounce klug verzögert}.
 * @param {Function} callback
 * @param {[]} deps
 * @param {number} [delay=167] - Standardmäßig auf `167` gesetzt, was "10 Frames bei 60 Hz" entspricht (`10 * (1000 / 60) ~= 167 ms`)
 */
export const useDebounced = (callback, deps, delay = 167) =>
  useMemo(() => smartDebounce(callback, delay), [...deps, delay])

1voto

Fareed Alnamrouti Punkte 28431

Für Throttle oder Debounce ist der beste Weg, eine Funktionscreator zu erstellen, damit du es überall verwenden kannst, zum Beispiel:

  updateUserProfileField(feldname) {
    const handler = throttle(wert => {
      console.log(feldname, wert);
    }, 400);
    return evt => handler(evt.target.value.trim());
  }

Und in deiner render Methode kannst du dies tun:

Die updateUserProfileField Methode wird jedes Mal eine separate Funktion erstellen, wenn du sie aufrufst.

Hinweis: Versuche nicht, den Handler direkt zurückzugeben. Zum Beispiel wird dies nicht funktionieren:

 updateUserProfileField(feldname) {
    return evt => throttle(wert => {
      console.log(feldname, wert);
    }, 400)(evt.target.value.trim());
  }

Der Grund, warum dies nicht funktionieren wird, ist weil dies jedes Mal eine neue Throttle-Funktion generieren wird, wenn das Ereignis aufgerufen wird, anstatt die gleiche Throttle-Funktion zu verwenden. Also wird die Throttle im Grunde nutzlos sein ;)

Außerdem, wenn du Debounce oder Throttle verwendest, brauchst du kein setTimeout oder clearTimeout. Das ist eigentlich der Grund, warum wir sie verwenden :P

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X