Jak przeprowadzasz debounce w React.js?
Chcę ogłosić uchwytOnChange.
Próbowałem z, debounce(this.handleOnChange, 200)
ale to nie działa.
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
źródło
źródło
debounce
. tutaj, kiedyonChange={debounce(this.handleOnChange, 200)}/>
będzie przywoływać zadebounce function
każdym razem. ale w rzeczywistości potrzebujemy wywołać funkcję, którą zwróciła funkcja debounce.Odpowiedzi:
2019: wypróbuj haki + zapowiedź obietnicy
To jest najbardziej aktualna wersja tego, jak rozwiązałbym ten problem. Użyłbym:
To jest trochę wstępne okablowanie, ale sam tworzysz prymitywne bloki i możesz zrobić swój własny hak, abyś musiał to zrobić tylko raz.
A potem możesz użyć haka:
Ten przykład znajduje się tutaj . Aby uzyskać więcej informacji, przeczytaj dokumentację przechwytującą reakcję asynchroniczną .
2018: spróbuj ogłosić obietnicę
Często chcemy ogłaszać wywołania interfejsu API, aby uniknąć zalania zaplecza niepotrzebnymi żądaniami.
W 2018 r. Praca z wywołaniami zwrotnymi (Lodash / Underscore) jest dla mnie zła i podatna na błędy. Łatwo jest napotkać problemy z podstawowymi funkcjami i współbieżnością, ponieważ wywołania API są rozwiązywane w dowolnej kolejności.
Stworzyłem małą bibliotekę z myślą o React, aby rozwiązać wasze problemy: niesamowita obietnica wypowiedzenia .
Nie powinno to być bardziej skomplikowane:
Zadeklarowana funkcja zapewnia, że:
this.setState({ result });
wydarzy się pojedynczy na każde wywołanie APIW końcu możesz dodać kolejną sztuczkę, jeśli twój komponent odmontuje:
Zauważ, że Observables (RxJS) może również doskonale nadawać się do ogłaszania danych wejściowych, ale jest to bardziej wydajna abstrakcja, która może być trudniejsza do nauczenia się / używania poprawnie.
<2017: Nadal chcesz korzystać z zapowiedzi wywołania zwrotnego?
Ważną częścią jest tutaj utworzenie jednej zadeklarowanej (lub ograniczonej) funkcji dla każdej instancji komponentu . Nie chcesz ponownie odtwarzać funkcji debounce (lub przepustnicy) za każdym razem i nie chcesz, aby wiele instancji współużytkowało tę samą funkcję debounce.
Nie definiuję funkcji ogłaszającej w tej odpowiedzi, ponieważ nie jest ona tak naprawdę istotna, ale ta odpowiedź będzie doskonale działać z
_.debounce
podkreśleniem lub lodash, a także z dowolną funkcją ogłaszającą podaną przez użytkownika.DOBRY POMYSŁ:
Ponieważ funkcje zapowiadane są stanowe, musimy utworzyć jedną funkcję zapowiedzianą na instancję składnika .
ES6 (właściwość klasy) : zalecane
ES6 (konstruktor klasy)
ES5
Zobacz JsFiddle : 3 instancje generują 1 pozycję dziennika na instancję (co daje 3 globalnie).
NIE jest to dobry pomysł:
To nie zadziała, ponieważ podczas tworzenia opisu klasy obiekt
this
nie jest sam obiekt utworzony.this.method
nie zwraca tego, czego oczekujesz, ponieważthis
kontekst nie jest samym obiektem (który tak naprawdę jeszcze nie istnieje BTW, ponieważ właśnie jest tworzony).NIE jest to dobry pomysł:
Tym razem efektywnie tworzysz zapowiadaną funkcję, która wywołuje Twoją
this.method
. Problem polega na tym, że odtwarzasz go przy każdymdebouncedMethod
wywołaniu, więc nowo utworzona funkcja usuwania nie wie nic o poprzednich połączeniach! Z czasem musisz ponownie użyć tej samej funkcji, która została ogłoszona, w przeciwnym razie ogłoszenie nie nastąpi.NIE jest to dobry pomysł:
To trochę trudne.
Wszystkie zamontowane instancje klasy będą miały tę samą zapowiedzianą funkcję i najczęściej nie jest to to, czego chcesz! Zobacz JsFiddle : 3 instancje produkują tylko 1 pozycję dziennika na całym świecie.
Musisz utworzyć funkcję, która została zadeklarowana dla każdej instancji składnika , a nie pojedynczą, zadeklarowaną funkcję na poziomie klasy, wspólną dla każdej instancji składnika.
Zadbaj o łączenie zdarzeń React
Jest to powiązane, ponieważ często chcemy ogłosić lub zdławić zdarzenia DOM.
W React obiekty zdarzeń (tj.
SyntheticEvent
), Które otrzymujesz w wywołaniach zwrotnych, są pulowane (jest to teraz udokumentowane ). Oznacza to, że po wywołaniu wywołania zwrotnego zdarzenia otrzymane SyntheticEvent zostanie ponownie umieszczone w puli z pustymi atrybutami w celu zmniejszenia presji GC.Jeśli więc uzyskujesz dostęp do
SyntheticEvent
właściwości asynchronicznie do pierwotnego wywołania zwrotnego (jak w przypadku dławienia / usuwania błędów), właściwości, do których masz dostęp, mogą zostać usunięte. Jeśli chcesz, aby zdarzenie nigdy nie było ponownie umieszczane w puli, możesz użyć tejpersist()
metody.Bez utrwalania (zachowanie domyślne: zdarzenie połączone)
Drugi (asynchroniczny) zostanie wydrukowany,
hasNativeEvent=false
ponieważ właściwości zdarzenia zostały wyczyszczone.Z wytrwałością
Drugi (asynchroniczny) zostanie wydrukowany,
hasNativeEvent=true
ponieważpersist
pozwala uniknąć ponownego umieszczenia zdarzenia w puli.Możesz przetestować te 2 zachowania tutaj: JsFiddle
Przeczytaj odpowiedź Julen, aby zobaczyć przykład korzystania
persist()
z funkcji przepustnicy / odbicia.źródło
handleOnChange = debounce((e) => { /* onChange handler code here */ }, timeout)
na najwyższym poziomie swojej klasy. Nadal skutecznie ustawiasz element instancji, ale wygląda to bardziej jak normalna definicja metody. Nie ma potrzeby,constructor
jeśli jeszcze go nie masz. Przypuszczam, że jest to przede wszystkim styl.componentWillUnmount
:this.method.cancel()
- w przeciwnym razie może chcieć ustawić parametr Stan na odmontowanym komponencie.Niekontrolowane komponenty
Możesz użyć tej
event.persist()
metody .Oto przykład użycia podkreślenia
_.debounce()
:Edycja: zobacz ten JSFiddle
Kontrolowane komponenty
Aktualizacja: powyższy przykład pokazuje niekontrolowany komponent . Cały czas używam kontrolowanych elementów, więc oto kolejny przykład powyższego, ale bez użycia
event.persist()
„oszustwa”.JSFiddle jest dostępny także. Przykład bez podkreślenia
Edycja: zaktualizowano przykłady i JSFiddles do React 0.12
Edycja: zaktualizowano przykłady w celu rozwiązania problemu podniesionego przez Sebastiena Lorbera
Edycja: zaktualizowano o jsfiddle, który nie używa podkreślenia i używa zwykłego debounce javascript.
źródło
<input value={this.props.someprop}...
to nie będzie renderowane poprawnie, ponieważ aktualizacja po naciśnięciu klawisza nie wróci do komponentu, aż po debounce. Można pominąć opcję,value=
jeśli jesteś zadowolony z tego, że nie można nią zarządzać, ale jeśli chcesz wstępnie wypełnić wartość i / lub powiązać ją gdzie indziej, to oczywiście nie działa.persist
zwłaszcza gdy może być wiele wydarzeń, na przykładmousemove
. Zauważyłem, że kod całkowicie przestał reagować w ten sposób. O wiele bardziej wydajne jest wyodrębnienie potrzebnych danych ze zdarzenia natywnego w wywołaniu zdarzenia, a następnie wywołanie funkcji debunowanej / dławionej tylko danymi, a NIE samego zdarzenia. Nie trzeba tak trwać w tym wydarzeniu2019: Użyj haka reagującego „useCallback”
Po wypróbowaniu wielu różnych podejść odkryłem, że używanie
useCallback
jest najprostszym i najbardziej wydajnym w rozwiązywaniu problemu wielu połączeńdebounce
w ramachonChange
zdarzenia.Zgodnie z dokumentacją interfejsu API Hooks ,
Przekazanie pustej tablicy jako zależności powoduje, że wywołanie zwrotne jest wywoływane tylko raz. Oto prosta implementacja:
Mam nadzieję że to pomoże!
źródło
debounce()
nie uważaonChange()
wywołania zwrotnego za tę samą metodę wywołania zwrotnego?const testFunc2 = useCallback(debounce((text) => console.log('testFunc2() has ran:', text), 1000) , []);
wewnątrz ciała komponentu funkcji lub React wyświetla komunikat o błędzie dotyczący użycia haka poza nim. Następnie wonChange
obsługi zdarzeń:<input type='text' name='name' className='th-input-container__input' onChange={evt => {testFunc2(evt.target.value);}}
.Uznałem ten post za Justina Tulka za bardzo pomocny. Po kilku próbach, w sposób, który można by uznać za bardziej oficjalny w przypadku reakcji / redux, pokazuje, że nie udaje się to z powodu syntetycznego łączenia zdarzeń React . Jego rozwiązanie wykorzystuje pewien stan wewnętrzny do śledzenia wartości zmienionej / wprowadzonej na wejściu, z oddzwanianiem zaraz po
setState
którym wywołuje dławioną / zadeklarowaną akcję redux, która pokazuje niektóre wyniki w czasie rzeczywistym.źródło
Jeśli wszystko, czego potrzebujesz od obiektu zdarzenia, to uzyskanie elementu wejściowego DOM, rozwiązanie jest znacznie prostsze - po prostu użyj
ref
. Pamiętaj, że wymaga to podkreślenia :źródło
Po chwili zmagania się z wprowadzaniem tekstu i samodzielnego znalezienia idealnego rozwiązania znalazłem to na npm: reakcja-debounce-input .
Oto prosty przykład:
Składnik DebounceInput akceptuje wszystkie rekwizyty, które można przypisać do normalnego elementu wejściowego. Wypróbuj to na codepen
Mam nadzieję, że pomaga to również komuś innemu i oszczędza mu trochę czasu.
źródło
Ze
debounce
trzeba zachować oryginalną imprezę z syntetycznego wokółevent.persist()
. Oto sprawdzony przykład działaniaReact 16+
.Dzięki komponentowi funkcjonalnemu możesz to zrobić -
Referencje - - https://gist.github.com/elijahmanor/08fc6c8468c994c844213e4a4344a709 - https://blog.revathskumar.com/2016/02/reactjs-using-debounce-in-react-components.html
źródło
Jeśli używasz redux, możesz to zrobić w bardzo elegancki sposób z oprogramowaniem pośrednim. Można zdefiniować
Debounce
oprogramowanie pośrednie jako:Następnie możesz dodać debugowanie do twórców akcji, takich jak:
W rzeczywistości jest już oprogramowanie pośrednie, które możesz pobrać npm, aby zrobić to za Ciebie.
źródło
applyMiddleware(...)
łańcuchu, jeśli mamy wieleKorzystanie ES6 klasie i React 15.xx & lodash.debounce Im przy reagować na bibl tu od strat Zdarzenie to wiążą wewnętrznie.
źródło
Wiele dobrych informacji już tutaj, ale by być zwięzłym. To działa dla mnie ...
źródło
_debounce
opakowanie, to zadziała. Uwielbiam ten pomysł!Możesz użyć metody debube Lodash https://lodash.com/docs/4.17.5#debounce . To jest proste i skuteczne.
Możesz także anulować metodę debounce przy użyciu poniższej metody.
Mam nadzieję, że to ci pomoże. Twoje zdrowie!!
źródło
Do Twojej wiadomości
Oto kolejna implementacja PoC:
Mam nadzieję, że to pomoże :)
źródło
Istnieje
use-debounce
pakiet, którego można używać z hakami ReactJS.Z pliku README:
Jak widać z powyższego przykładu, skonfigurowano aktualizowanie zmiennej
value
tylko raz na sekundę (1000 milisekund).źródło
Kolejny wariant z najnowszą reakcją i laszowaniem.
źródło
Ładne i czyste rozwiązanie, które nie wymaga żadnych zewnętrznych zależności:
Ogłaszanie za pomocą React Hooks
Korzysta z niestandardowego haczyka useEffect React i metody
setTimeout
/clearTimeout
.źródło
Próbowałeś?
źródło
Zamiast zawijać uchwytOnChange w debounce (), dlaczego nie zawijać wywołania ajax wewnątrz funkcji zwrotnej w debounce, nie niszcząc w ten sposób obiektu zdarzenia. Więc coś takiego:
źródło
Oto przykład, który wymyśliłem, który otacza inną klasę debugującym. To ładnie nadaje się do przekształcenia w dekorator / funkcję wyższego rzędu:
źródło
Istnieje teraz inne rozwiązanie dla React i React Native pod koniec 2019 r . :
składnik Reag-debounce
Jest to komponent, łatwy w użyciu, mały i obsługiwany szeroko
Przykład:
* Jestem twórcą tego komponentu
źródło
Szukałem rozwiązania tego samego problemu i natknąłem się na ten wątek, a także niektóre inne, ale miały one ten sam problem: jeśli próbujesz wykonać
handleOnChange
funkcję i potrzebujesz wartości z celu zdarzenia, dostanieszcannot read property value of null
lub trochę taki błąd. W moim przypadku musiałem także zachować kontekstthis
funkcji, która została zadeklarowana, ponieważ wykonuję płynną akcję. Oto moje rozwiązanie, działa dobrze w moim przypadku użycia, więc zostawiam je tutaj na wypadek, gdyby ktoś natknął się na ten wątek:źródło
za
throttle
czydebounce
najlepszym sposobem jest stworzenie twórca funkcji, dzięki czemu można go używać w każdym miejscu, na przykład:a swoją
render
metodą możesz wykonać:updateUserProfileField
metoda stworzy wydzieloną funkcję za każdym razem to nazwać.Uwaga : nie próbuj zwracać modułu obsługi bezpośrednio, na przykład to nie zadziała:
powód, dla którego to nie zadziała, ponieważ spowoduje to wygenerowanie nowej funkcji przepustnicy za każdym razem, gdy wywołane zostanie zdarzenie zamiast używania tej samej funkcji przepustnicy, więc w zasadzie przepustnica będzie bezużyteczna;)
Również, jeśli używasz
debounce
lubthrottle
nie potrzebujeszsetTimeout
lubclearTimeout
, właśnie dlatego ich używamy: P.źródło
Oto fragment kodu wykorzystujący podejście @ Abry zawinięte w komponent funkcji (używamy struktury dla interfejsu użytkownika, wystarczy zastąpić go prostym przyciskiem)
źródło
Moje rozwiązanie jest oparte na hakach (napisane maszynowym skryptem).
Mam 2 główne zaczepy
useDebouncedValue
iuseDebouncedCallback
Pierwszy -
useDebouncedValue
Załóżmy, że mamy pole wyszukiwania, ale chcemy zapytać serwer o wyniki wyszukiwania po tym, jak użytkownik przestanie pisać przez 0,5 s
Realizacja
druga
useDebouncedCallback
Po prostu tworzy funkcję „ogłosiania” w zakresie twojego komponentu.
Powiedzmy, że mamy komponent z przyciskiem, który wyświetli alert 500 ms po tym, jak przestałeś go klikać.
Implementacja (uwaga: używam lodash / debounce jako pomocnika)
źródło
Oto działający przykład TypeScript dla tych, którzy używają TS i chcą ogłosić
async
funkcje.źródło
trochę tu późno, ale to powinno pomóc. utwórz tę klasę (jest napisana pismem maszynowym, ale łatwo ją przekonwertować na javascript)
i do użycia
źródło
możesz użyć tlence tlence
źródło
Rozwiązanie Julena jest dość trudne do odczytania, tutaj jest bardziej przejrzysty i konkretny kod reagowania dla każdego, kto potknął się o niego na podstawie tytułu, a nie drobnych szczegółów pytania.
wersja tl; dr : kiedy zaktualizujesz do obserwatorów, wyślij zamiast tego wywołanie metody harmonogramu, która z kolei powiadomi obserwatorów (lub wykona ajax itp.)
Uzupełnij jsfiddle przykładowym komponentem jsfiddle
źródło
Unikaj używania
event.persist()
- chcesz pozwolić React przetworzyć syntetyczne zdarzenie. Myślę, że najczystszym sposobem korzystania z klas lub haków jest podzielenie wywołania zwrotnego na dwie części:Klasy
Funkcje
Zauważ, że jeśli twoja
handleMouseOver
funkcja używa stanu z komponentu, powinieneś użyćuseMemo
zamiastuseRef
i przekazać je jako zależności, w przeciwnym razie będziesz pracować z nieaktualnymi danymi (nie dotyczy to oczywiście klas).źródło
Przedłuż hak useState
Użyj haka
https://trippingoncode.com/react-debounce-hook/
źródło
Spotkałem ten problem dzisiaj. Rozwiązano to za pomocą
setTimeout
iclearTimeout
.Podam przykład, który możesz dostosować:
Można go również refaktoryzować we własnym komponencie funkcyjnym:
I używaj go w następujący sposób:
źródło