Wie führt man ein Debounce in React.js durch?
Ich möchte das handleOnChange entprellen.
Ich habe es versucht, debounce(this.handleOnChange, 200)
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 <input type="search" name="p" onChange={this.handleOnChange} />;
},
handleOnChange: function(event) {
// make ajax call
}
});
javascript
reactjs
Chetan Ankola
quelle
quelle
debounce
. hier, wannonChange={debounce(this.handleOnChange, 200)}/>
, wird esdebounce function
jedes Mal aufgerufen . Tatsächlich müssen wir jedoch die Funktion aufrufen, die die Entprellungsfunktion zurückgegeben hat.Antworten:
2019: versuchen Sie Hooks + Versprechen Entprellen
Dies ist die aktuellste Version, wie ich dieses Problem lösen würde. Ich würde ... benutzen:
Dies ist eine anfängliche Verkabelung, aber Sie erstellen selbst primitive Blöcke, und Sie können Ihren eigenen benutzerdefinierten Hook erstellen, sodass Sie dies nur einmal tun müssen.
Und dann können Sie Ihren Haken benutzen:
Dieses Beispiel wird hier ausgeführt. Weitere Informationen finden Sie in der Dokumentation zum React-Async-Hook .
2018: Versuchen Sie, das Versprechen zu entprellen
Wir möchten häufig API-Aufrufe entprellen, um zu vermeiden, dass das Backend mit nutzlosen Anforderungen überflutet wird.
Im Jahr 2018 fühlt sich die Arbeit mit Rückrufen (Lodash / Underscore) für mich schlecht und fehleranfällig an. Aufgrund von API-Aufrufen, die in einer beliebigen Reihenfolge gelöst werden, können Probleme mit Boilerplate und Parallelität leicht auftreten.
Ich habe eine kleine Bibliothek mit dem Gedanken an React erstellt, um Ihre Probleme zu lösen: Awesome-Debounce-Versprechen .
Dies sollte nicht komplizierter sein:
Die entprellte Funktion stellt sicher, dass:
this.setState({ result });
Pro API-Aufruf wird eine einzige ausgeführtMöglicherweise können Sie einen weiteren Trick hinzufügen, wenn die Bereitstellung Ihrer Komponente aufgehoben wird:
Beachten Sie, dass Observables (RxJS) auch gut zum Entprellen von Eingaben geeignet sind, aber eine leistungsfähigere Abstraktion ist, die möglicherweise schwieriger zu erlernen / richtig zu verwenden ist.
<2017: Möchten Sie das Callback-Debouncing weiterhin verwenden?
Der wichtige Teil hierbei ist das Erstellen einer einzelnen entprellen (oder gedrosselten) Funktion pro Komponenteninstanz . Sie möchten die Entprellungs- (oder Drossel-) Funktion nicht jedes Mal neu erstellen, und Sie möchten nicht, dass mehrere Instanzen dieselbe entprellende Funktion gemeinsam nutzen.
Ich definiere in dieser Antwort keine Entprellungsfunktion, da sie nicht wirklich relevant ist, aber diese Antwort funktioniert perfekt mit
_.debounce
Unterstrichen oder Lodash sowie mit allen vom Benutzer bereitgestellten Entprellungsfunktionen.GUTE IDEE:
Da entprellte Funktionen statusbehaftet sind, müssen wir eine entprellte Funktion pro Komponenteninstanz erstellen .
ES6 (Klasseneigenschaft) : empfohlen
ES6 (Klassenkonstruktor)
ES5
Siehe JsFiddle : 3 Instanzen erzeugen 1 Protokolleintrag pro Instanz (das sind 3 global).
Keine gute Idee:
Dies funktioniert nicht, da bei der Klassenbeschreibung die Objekterstellung
this
nicht das selbst erstellte Objekt ist.this.method
gibt nicht zurück, was Sie erwarten, da derthis
Kontext nicht das Objekt selbst ist (das tatsächlich noch nicht wirklich existiert, übrigens, da es gerade erstellt wird).Keine gute Idee:
Dieses Mal erstellen Sie effektiv eine entprellte Funktion, die Ihre aufruft
this.method
. Das Problem ist, dass Sie es bei jedemdebouncedMethod
Anruf neu erstellen, sodass die neu erstellte Entprellungsfunktion nichts über frühere Anrufe weiß! Sie müssen dieselbe entprellte Funktion im Laufe der Zeit wiederverwenden, da sonst sonst keine Entprellung erfolgt.Keine gute Idee:
Das ist hier etwas knifflig.
Alle gemounteten Instanzen der Klasse haben dieselbe entprellte Funktion, und meistens ist dies nicht das, was Sie wollen!. Siehe JsFiddle : 3 Instanzen produzieren weltweit nur 1 Protokolleintrag.
Sie müssen für jede Komponenteninstanz eine entprellte Funktion erstellen und nicht eine einzelne entprellte Funktion auf Klassenebene, die von jeder Komponenteninstanz gemeinsam genutzt wird.
Kümmere dich um das Event-Pooling von React
Dies hängt damit zusammen, dass wir DOM-Ereignisse häufig entprellen oder drosseln möchten.
In React werden die Ereignisobjekte (dh
SyntheticEvent
), die Sie in Rückrufen erhalten, zusammengefasst (dies ist jetzt dokumentiert ). Dies bedeutet, dass nach dem Aufruf des Ereignisrückrufs das empfangene SyntheticEvent mit leeren Attributen wieder in den Pool gestellt wird, um den GC-Druck zu verringern.Wenn Sie also
SyntheticEvent
asynchron auf Eigenschaften des ursprünglichen Rückrufs zugreifen (wie dies beim Drosseln / Entprellen der Fall sein kann), werden die Eigenschaften, auf die Sie zugreifen, möglicherweise gelöscht. Wenn Sie möchten, dass das Ereignis nie wieder in den Pool aufgenommen wird, können Sie diepersist()
Methode verwenden.Ohne Persistenz (Standardverhalten: gepooltes Ereignis)
Der zweite (asynchron) wird gedruckt,
hasNativeEvent=false
da die Ereigniseigenschaften bereinigt wurden.Mit bestehen
Der zweite (asynchron) wird gedruckt,
hasNativeEvent=true
dapersist
Sie vermeiden können, dass das Ereignis wieder in den Pool verschoben wird .Sie können diese beiden Verhaltensweisen hier testen : JsFiddle
In Julens Antwort finden Sie ein Beispiel für die Verwendung
persist()
mit einer Gas- / Entprellfunktion.quelle
handleOnChange = debounce((e) => { /* onChange handler code here */ }, timeout)
auf der obersten Ebene Ihrer Klasse tun können . Sie legen immer noch effektiv ein Instanzmitglied fest, aber es ähnelt eher einer normalen Methodendefinition. Keine Notwendigkeit für eine,constructor
wenn Sie noch keine definiert haben. Ich nehme an, es ist meistens eine Stilpräferenz.componentWillUnmount
:this.method.cancel()
- Andernfalls möchte sie möglicherweise den Status für eine nicht gemountete Komponente festlegen.Unkontrollierte Komponenten
Sie können die
event.persist()
Methode verwenden .Es folgt ein Beispiel mit Unterstrichen
_.debounce()
:Bearbeiten: Siehe diese JSFiddle
Kontrollierte Komponenten
Update: Das obige Beispiel zeigt eine unkontrollierte Komponente . Ich benutze die ganze Zeit kontrollierte Elemente, daher hier ein weiteres Beispiel für das oben
event.persist()
Genannte , aber ohne den "Trick" zu verwenden.Eine JSFiddle ist ebenfalls verfügbar . Beispiel ohne Unterstrich
Bearbeiten: Aktualisierte Beispiele und JSFiddles to React 0.12
Bearbeiten: Aktualisierte Beispiele, um das von Sebastien Lorber aufgeworfene Problem zu beheben
Bearbeiten: aktualisiert mit jsfiddle, das keinen Unterstrich verwendet und einfaches Javascript-Debounce verwendet.
quelle
<input value={this.props.someprop}...
, wird es nicht richtig gerendert, da das Update beim Tastendruck erst nach dem Entprellen wieder in die Komponente zurückkehrt. Es ist in Ordnung, das wegzulassen,value=
wenn Sie froh sind, dass dies nicht verwaltet wird, aber wenn Sie den Wert vorab ausfüllen und / oder an eine andere Stelle binden möchten, funktioniert dies offensichtlich nicht.persist
insbesondere wenn es viele Ereignisse gibt, wie zmousemove
. Ich habe gesehen, dass Code auf diese Weise völlig nicht mehr reagiert. Es ist viel effizienter, die erforderlichen Daten aus dem nativen Ereignis im Ereignisaufruf zu extrahieren und dann die entprellte / gedrosselte Funktion nur mit den Daten aufzurufen, NICHT mit dem Ereignis selbst. Keine Notwendigkeit, das Ereignis auf diese Weise2019: Verwenden Sie den Reaktionshaken 'useCallback'
Nachdem ich viele verschiedene Ansätze ausprobiert hatte, stellte ich fest
useCallback
, dass die Verwendung am einfachsten und effizientesten ist, um das Problem der Verwendung mehrerer Anrufedebounce
innerhalb einesonChange
Ereignisses zu lösen .Gemäß der Dokumentation Hooks API ,
Durch Übergeben eines leeren Arrays als Abhängigkeit wird sichergestellt, dass der Rückruf nur einmal aufgerufen wird. Hier ist eine einfache Implementierung:
Hoffe das hilft!
quelle
debounce()
nicht die betrachtenonChange()
Rückruf die gleiche Callback - Methode zu sein?const testFunc2 = useCallback(debounce((text) => console.log('testFunc2() has ran:', text), 1000) , []);
innerhalb des Hauptteils der Funktionskomponente verschieben, oder React gibt eine Fehlermeldung über die Verwendung von Hooks außerhalb der Funktionskomponente aus. Dann imonChange
Event-Handler :<input type='text' name='name' className='th-input-container__input' onChange={evt => {testFunc2(evt.target.value);}}
.Ich fand diesen Beitrag von Justin Tulk sehr hilfreich. Nach ein paar Versuchen, wie man es bei React / Redux als offizieller empfinden würde, zeigt sich, dass es aufgrund des Pools synthetischer Ereignisse von React fehlschlägt . Seine Lösung verwendet dann einen internen Status, um den in der Eingabe geänderten / eingegebenen Wert zu verfolgen
setState
, und ruft direkt danach eine gedrosselte / entprellende Redux-Aktion auf, die einige Ergebnisse in Echtzeit anzeigt.quelle
Wenn Sie vom Ereignisobjekt nur das DOM-Eingabeelement abrufen müssen, ist die Lösung viel einfacher - verwenden Sie einfach
ref
. Beachten Sie, dass hierfür ein Unterstrich erforderlich ist :quelle
Nachdem ich eine Weile mit den Texteingaben zu kämpfen hatte und selbst keine perfekte Lösung gefunden hatte, fand ich dies auf npm: React-Debounce-Input .
Hier ist ein einfaches Beispiel:
Die DebounceInput-Komponente akzeptiert alle Requisiten, die Sie einem normalen Eingabeelement zuweisen können. Probieren Sie es auf Codepen aus
Ich hoffe, es hilft auch jemand anderem und spart ihm Zeit.
quelle
Mit müssen
debounce
Sie das ursprüngliche synthetische Ereignis mit behaltenevent.persist()
. Hier ist ein Arbeitsbeispiel getestet mitReact 16+
.Mit der Funktionskomponente können Sie dies tun -
Referenzen - - https://gist.github.com/elijahmanor/08fc6c8468c994c844213e4a4344a709 - https://blog.revathskumar.com/2016/02/reactjs-using-debounce-in-react-components.html
quelle
Wenn Sie Redux verwenden, können Sie dies mit Middleware auf sehr elegante Weise tun. Sie können eine
Debounce
Middleware wie folgt definieren :Anschließend können Sie Aktionserstellern Entprellungen hinzufügen, z.
Es gibt tatsächlich bereits Middleware, mit der Sie npm aussteigen können, um dies für Sie zu tun.
quelle
applyMiddleware(...)
Kette ausgeführt wird , wenn wir viele habenVerwenden von ES6 CLASS und React 15.xx & lodash.debounce Ich verwende hier die Refs von React, da Ereignisverluste dies intern binden.
quelle
Viele gute Infos hier schon, aber um es kurz zu machen. Das funktioniert bei mir ...
quelle
_debounce
Wrapper entferne , funktioniert es. Ich liebe diese Idee!Sie können die Lodash-Debounce- Methode https://lodash.com/docs/4.17.5#debounce verwenden. Es ist einfach und effektiv.
Sie können die Entprellungsmethode auch mit der folgenden Methode abbrechen.
Hoffe es hilft dir. Prost!!
quelle
Zu Ihrer Information
Hier ist eine weitere PoC-Implementierung:
Ich hoffe, es hilft :)
quelle
Es gibt ein
use-debounce
Paket, das Sie mit ReactJS-Hooks verwenden können.Aus der README-Datei des Pakets:
Wie Sie dem obigen Beispiel entnehmen können, wird die Variable
value
nur einmal pro Sekunde (1000 Millisekunden) aktualisiert .quelle
Nur eine weitere Variante mit neueren Reaktionen und Lodash.
quelle
Eine schöne und saubere Lösung, die keine externen Abhängigkeiten erfordert:
Entprellen mit React Hooks
Es verwendet ein benutzerdefiniertes Plus sowie die useEffect React-Hooks und die
setTimeout
/clearTimeout
-Methode.quelle
Hast du versucht?
quelle
Anstatt den handleOnChange in ein debounce () zu verpacken, sollten Sie den Ajax-Aufruf in die Rückruffunktion in das Entprellen einbinden und dabei das Ereignisobjekt nicht zerstören. Also so etwas wie das:
quelle
Hier ist ein Beispiel, das ich mir ausgedacht habe und das eine andere Klasse mit einem Debouncer umschließt. Dies eignet sich gut, um zu einer Dekorateur- / Funktion höherer Ordnung gemacht zu werden:
quelle
Es gibt jetzt eine andere Lösung für React and React Native Ende 2019 :
React-Debounce-Komponente
Es ist eine Komponente, einfach zu bedienen, winzig und breit unterstützt
Beispiel:
* Ich bin der Schöpfer dieser Komponente
quelle
Ich habe nach einer Lösung für das gleiche Problem gesucht und bin auf diesen und einige andere Threads gestoßen, aber sie hatten das gleiche Problem: Wenn Sie versuchen, eine
handleOnChange
Funktion auszuführen, und Sie den Wert eines Ereignisziels benötigen, erhalten Siecannot read property value of null
oder einige ein solcher Fehler. In meinem Fall musste ich auch den Kontextthis
innerhalb der entprellten Funktion beibehalten, da ich eine fließfähige Aktion ausführe. Hier ist meine Lösung, sie funktioniert gut für meinen Anwendungsfall, also lasse ich sie hier, falls jemand auf diesen Thread stößt:quelle
zum
throttle
oderdebounce
am besten erstellen Sie einen Funktionsersteller, damit Sie ihn überall verwenden können, zum Beispiel:und in deinem
render
Methode können Sie tun:das
updateUserProfileField
Methode erstellt bei jedem Aufruf eine separate Funktion.Hinweis: Versuchen Sie nicht, den Handler direkt zurückzugeben. Dies funktioniert beispielsweise nicht:
der Grund, warum dies nicht funktioniert, weil dies jedes Mal eine neue Drosselfunktion erzeugt, wenn das Ereignis aufgerufen wird, anstatt dieselbe Drosselfunktion zu verwenden, so dass die Drossel im Grunde genommen unbrauchbar ist;)
Auch wenn Sie verwenden
debounce
oderthrottle
nicht benötigensetTimeout
oderclearTimeout
, verwenden wir sie tatsächlich aus diesem Grund: P.quelle
Hier ist ein Ausschnitt aus dem Ansatz von @ Abra, der in eine Funktionskomponente eingeschlossen ist (wir verwenden Fabric für die Benutzeroberfläche, ersetzen Sie ihn einfach durch eine einfache Schaltfläche).
quelle
Meine Lösung basiert auf Hooks (geschrieben in Typescript).
Ich habe 2 Haupthaken
useDebouncedValue
unduseDebouncedCallback
Zuerst -
useDebouncedValue
Angenommen, wir haben ein Suchfeld, aber wir möchten den Server nach Suchergebnissen fragen, nachdem der Benutzer für 0,5 Sekunden aufgehört hat zu tippen
Implementierung
Zweite
useDebouncedCallback
Es wird lediglich eine "entprellte" Funktion im Bereich Ihrer Komponente erstellt.
Angenommen, wir haben eine Komponente mit einer Schaltfläche, die 500 ms nach dem Klicken darauf eine Warnung anzeigt.
Implementierung (Hinweis Ich verwende lodash / debounce als Helfer)
quelle
Hier ist ein funktionierendes TypeScript-Beispiel für diejenigen, die TS verwenden und
async
Funktionen entprellen möchten .quelle
ein bisschen spät hier, aber das sollte helfen. Erstellen Sie diese Klasse (sie ist in Typoskript geschrieben, aber einfach in Javascript zu konvertieren).
und zu verwenden
quelle
Sie können tlence tlence verwenden
quelle
Die Julen-Lösung ist schwer zu lesen. Hier ist ein klarerer und präziser Reaktionscode für alle, die ihn aufgrund des Titels und nicht aufgrund der winzigen Details der Frage gestolpert haben.
tl; dr version : Wenn Sie ein Update an Beobachter senden würden, rufen Sie stattdessen eine Zeitplanmethode auf, die die Beobachter tatsächlich benachrichtigt (oder Ajax usw. ausführt).
Vervollständige jsfiddle mit der Beispielkomponente jsfiddle
quelle
Vermeiden
event.persist()
Sie die Verwendung - Sie möchten, dass React das synthetische Ereignis recycelt. Ich denke, der sauberste Weg, ob Sie Klassen oder Hooks verwenden, besteht darin, den Rückruf in zwei Teile aufzuteilen:Klassen
Funktionen
Beachten Sie, dass Sie, wenn Ihre
handleMouseOver
Funktion den Status innerhalb der Komponente verwendet, dieseuseMemo
anstelle vonuseRef
und als Abhängigkeiten übergeben sollten, da Sie sonst mit veralteten Daten arbeiten (gilt natürlich nicht für Klassen).quelle
Erweitern Sie den useState-Hook
Haken verwenden
https://trippingoncode.com/react-debounce-hook/
quelle
Habe dieses Problem heute getroffen. Es wurde mit
setTimeout
und gelöstclearTimeout
.Ich werde ein Beispiel geben, das Sie anpassen könnten:
Sie können es auch in einer eigenen Funktionskomponente umgestalten:
Und benutze es wie:
quelle