Bagaimana Anda melakukan debounce di React.js?
Saya ingin melemahkan handleOnChange.
Saya sudah mencoba debounce(this.handleOnChange, 200)
tetapi tidak berhasil.
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
sumber
sumber
debounce
. di sini, kapanonChange={debounce(this.handleOnChange, 200)}/>
, itu akan memanggildebounce function
setiap waktu. tetapi, pada kenyataannya, yang kita butuhkan adalah memanggil fungsi apa fungsi debounce dikembalikan.Jawaban:
2019: coba kait + janji tolak
Ini adalah versi terbaru tentang bagaimana saya akan menyelesaikan masalah ini. Saya akan menggunakan:
Ini adalah beberapa pengkabelan awal tetapi Anda membuat blok primitif sendiri, dan Anda dapat membuat kait kustom Anda sendiri sehingga Anda hanya perlu melakukan ini satu kali.
Dan kemudian Anda bisa menggunakan hook Anda:
Anda akan menemukan contoh ini berjalan di sini dan Anda harus membaca dokumentasi react-async-hook untuk lebih jelasnya.
2018: cobalah berjanji untuk melonggarkan
Kami sering ingin mendebo panggilan API untuk menghindari membanjiri backend dengan permintaan yang tidak berguna.
Pada tahun 2018, bekerja dengan callback (Lodash / Underscore) terasa buruk dan rentan kesalahan bagi saya. Sangat mudah untuk menemukan masalah boilerplate dan konkurensi karena penyelesaian panggilan API dalam urutan arbitrer.
Saya telah membuat perpustakaan kecil dengan React dalam pikiran untuk menyelesaikan rasa sakit Anda: mengagumkan-debounce-janji .
Ini seharusnya tidak lebih rumit dari itu:
Fungsi yang didebok memastikan bahwa:
this.setState({ result });
akan terjadi per panggilan APIAkhirnya, Anda dapat menambahkan trik lain jika komponen Anda dilepas:
Perhatikan bahwa Observables (RxJS) juga bisa sangat cocok untuk mendebit input, tetapi ini adalah abstraksi yang lebih kuat yang mungkin lebih sulit untuk dipelajari / digunakan dengan benar.
<2017: masih ingin menggunakan pembatalan panggilan balik?
Bagian penting di sini adalah membuat fungsi debouncing tunggal (atau dibatasi) per instance komponen . Anda tidak ingin membuat ulang fungsi debounce (atau throttle) setiap kali, dan Anda tidak ingin salah satu dari beberapa instance berbagi fungsi debounce yang sama.
Saya tidak mendefinisikan fungsi debouncing dalam jawaban ini karena itu tidak benar-benar relevan, tetapi jawaban ini akan berfungsi dengan baik dengan
_.debounce
garis bawah atau lodash, serta fungsi debouncing yang disediakan pengguna.IDE BAGUS:
Karena fungsi yang di-debo-kan adalah stateful, kita harus membuat satu fungsi yang di-debo-kan per instance komponen .
ES6 (properti kelas) : direkomendasikan
ES6 (konstruktor kelas)
ES5
Lihat JsFiddle : 3 instance menghasilkan 1 entri log per instance (yang menghasilkan 3 global).
BUKAN ide yang bagus:
Ini tidak akan berfungsi, karena selama pembuatan objek deskripsi kelas,
this
bukan objek yang dibuat sendiri.this.method
tidak mengembalikan apa yang Anda harapkan karenathis
konteksnya bukan objek itu sendiri (yang sebenarnya belum benar-benar ada BTW karena baru saja dibuat).BUKAN ide yang bagus:
Kali ini Anda secara efektif membuat fungsi terbebas yang memanggil Anda
this.method
. Masalahnya adalah Anda membuat ulang pada setiapdebouncedMethod
panggilan, sehingga fungsi debounce yang baru dibuat tidak tahu apa-apa tentang panggilan sebelumnya! Anda harus menggunakan kembali fungsi debouncing yang sama dari waktu ke waktu atau debouncing tidak akan terjadi.BUKAN ide yang bagus:
Ini agak sulit di sini.
Semua instance yang terpasang dari kelas akan berbagi fungsi yang sama, dan paling sering ini bukan yang Anda inginkan !. Lihat JsFiddle : 3 instance hanya menghasilkan 1 entri log secara global.
Anda harus membuat fungsi terbebas untuk setiap instance komponen , dan bukan fungsi terbebas tunggal di tingkat kelas, dibagikan oleh setiap instance komponen.
Jaga pooling acara React
Ini terkait karena kita sering ingin men-debo atau mencekik acara DOM.
Di Bereaksi, objek acara (yaitu,
SyntheticEvent
) yang Anda terima di panggilan balik dikumpulkan (ini sekarang didokumentasikan ). Ini berarti bahwa setelah event callback dipanggil, SyntheticEvent yang Anda terima akan dimasukkan kembali ke kolam dengan atribut kosong untuk mengurangi tekanan GC.Jadi, jika Anda mengakses
SyntheticEvent
properti secara tidak sinkron ke callback asli (seperti yang terjadi jika Anda mencekik / debounce), properti yang Anda akses dapat dihapus. Jika Anda ingin acara tersebut tidak dimasukkan kembali ke dalam kolam, Anda dapat menggunakanpersist()
metode ini.Tanpa bertahan (perilaku default: acara gabungan)
Kedua (async) akan mencetak
hasNativeEvent=false
karena properti acara telah dibersihkan.Dengan bertahan
Kedua (async) akan mencetak
hasNativeEvent=true
karenapersist
memungkinkan Anda untuk menghindari meletakkan kembali acara di kolam.Anda dapat menguji 2 perilaku ini di sini: JsFiddle
Baca jawaban Julen untuk contoh penggunaan
persist()
dengan fungsi throttle / debounce.sumber
handleOnChange = debounce((e) => { /* onChange handler code here */ }, timeout)
di tingkat atas kelas Anda. Anda masih secara efektif menetapkan anggota instance tetapi terlihat sedikit lebih seperti definisi metode normal. Tidak perlu untukconstructor
jika Anda belum memilikinya. Saya kira itu sebagian besar preferensi gaya.componentWillUnmount
:this.method.cancel()
- jika tidak, mungkin ingin mengaturState pada komponen unmount.Komponen yang Tidak Terkendali
Anda dapat menggunakan
event.persist()
metode ini .Contoh berikut menggunakan garis bawah
_.debounce()
:Sunting: Lihat JSFiddle ini
Komponen Terkendali
Pembaruan: contoh di atas menunjukkan komponen yang tidak terkontrol . Saya menggunakan elemen terkontrol sepanjang waktu jadi inilah contoh lain di atas, tetapi tanpa menggunakan
event.persist()
"tipuan".Sebuah JSFiddle tersedia juga. Contoh tanpa garis bawah
Edit: contoh diperbarui dan JSFiddles untuk Bereaksi 0,12
Sunting: contoh diperbarui untuk mengatasi masalah yang diangkat oleh Sebastien Lorber
Sunting: diperbarui dengan jsfiddle yang tidak menggunakan garis bawah dan menggunakan debounce javascript biasa.
sumber
<input value={this.props.someprop}...
maka itu tidak akan ditampilkan dengan benar karena pembaruan pada penekanan tombol tidak membuatnya kembali ke komponen sampai setelah debounce. Tidak masalah untuk menghapusvalue=
jika Anda senang ini tidak dikelola, tetapi jika Anda ingin mempopulasikan nilai dan / atau mengikatnya di tempat lain maka jelas ini tidak berhasil.persist
terutama ketika mungkin ada banyak acara, seperti padamousemove
. Saya telah melihat kode menjadi benar-benar tidak responsif seperti itu. Jauh lebih efisien untuk mengekstrak data yang diperlukan dari acara asli dalam panggilan acara, dan kemudian memanggil fungsi debouncing / dibatasi dengan data saja, BUKAN acara itu sendiri. Tidak perlu2019: Gunakan kait reaksi 'useCallback'
Setelah mencoba banyak pendekatan yang berbeda, saya menemukan menggunakan
useCallback
menjadi yang paling sederhana dan paling efisien untuk menyelesaikan masalah beberapa panggilan menggunakandebounce
dalam suatuonChange
peristiwa.Sesuai dokumentasi Hooks API ,
Melewati array kosong sebagai ketergantungan memastikan callback dipanggil hanya sekali. Berikut ini adalah implementasi sederhana:
Semoga ini membantu!
sumber
debounce()
menganggaponChange()
callback sebagai metode panggilan balik yang sama?const testFunc2 = useCallback(debounce((text) => console.log('testFunc2() has ran:', text), 1000) , []);
di dalam tubuh komponen fungsi atau Bereaksi output pesan kesalahan tentang penggunaan hook di luar itu. Kemudian padaonChange
event handler:<input type='text' name='name' className='th-input-container__input' onChange={evt => {testFunc2(evt.target.value);}}
.Saya menemukan posting ini oleh Justin Tulk sangat membantu. Setelah beberapa upaya, dalam apa yang orang anggap sebagai cara yang lebih resmi dengan reaksi / reduks, itu menunjukkan bahwa itu gagal karena penyatuan acara sintetis React . Solusinya kemudian menggunakan beberapa keadaan internal untuk melacak nilai yang diubah / dimasukkan dalam input, dengan panggilan balik setelah
setState
itu memanggil tindakan redux yang dibatasi / dideboed yang menunjukkan beberapa hasil secara realtime.sumber
Jika yang Anda butuhkan dari objek acara adalah untuk mendapatkan elemen input DOM, solusinya jauh lebih sederhana - cukup gunakan
ref
. Perhatikan bahwa ini memerlukan Garis Bawah :sumber
Setelah berjuang dengan input teks untuk sementara waktu dan tidak menemukan solusi yang sempurna pada saya sendiri, saya menemukan ini di npm: react-debounce-input .
Ini adalah contoh sederhana:
Komponen DebounceInput menerima semua alat peraga yang dapat Anda tetapkan untuk elemen input normal. Cobalah di codepen
Saya harap ini membantu orang lain juga dan menghemat waktu mereka.
sumber
Dengan
debounce
Anda perlu menjaga acara sintetis asli denganevent.persist()
. Berikut ini contoh kerja yang diujiReact 16+
.Dengan komponen fungsional, Anda dapat melakukan ini -
Referensi - - https://gist.github.com/elijahmanor/08fc6c8468c994c844213e4a4344a709 - https://blog.revathskumar.com/2016/02/reactjs-using-debounce-in-react-components.html
sumber
Jika Anda menggunakan redux, Anda bisa melakukan ini dengan cara yang sangat elegan dengan middleware. Anda dapat mendefinisikan
Debounce
middleware sebagai:Anda kemudian dapat menambahkan debouncing ke pembuat tindakan, seperti:
Sebenarnya sudah ada middleware Anda bisa keluar npm untuk melakukan ini untuk Anda.
sumber
applyMiddleware(...)
rantai jika kita memiliki banyakMenggunakan ES6 CLASS dan React 15.xx & lodash.debounce Saya menggunakan referensi React di sini karena peristiwa kehilangan ini mengikat secara internal.
sumber
Banyak info bagus sudah ada di sini, tetapi harus singkat. Ini bekerja untuk saya ...
sumber
_debounce
pembungkusnya berfungsi. Saya suka ide ini!Anda dapat menggunakan Lodash debounce https://lodash.com/docs/4.17.5#debounce metode. Ini sederhana dan efektif.
Anda juga dapat membatalkan metode debounce dengan menggunakan metode di bawah ini.
Semoga ini bisa membantu Anda. Bersulang!!
sumber
FYI
Berikut ini adalah implementasi PoC lainnya:
Saya harap ini membantu :)
sumber
Ada
use-debounce
paket yang bisa Anda gunakan dengan kait ReactJS.Dari README paket:
Seperti yang Anda lihat dari contoh di atas, sudah diatur untuk memperbarui variabel
value
hanya sekali setiap detik (1000 milidetik).sumber
Hanya varian lain dengan reaksi dan lodash terbaru.
sumber
Solusi yang bagus dan bersih, yang tidak memerlukan dependensi eksternal:
Debouncing dengan React Hooks
Menggunakan custom plus useEffect React hooks dan
setTimeout
/clearTimeout
method.sumber
Apakah kamu sudah mencoba?
sumber
Alih-alih membungkus handleOnChange dalam debounce (), mengapa tidak membungkus panggilan ajax di dalam fungsi callback di dalam debounce, sehingga tidak merusak objek acara. Jadi sesuatu seperti ini:
sumber
Berikut adalah contoh yang saya buat dengan membungkus kelas lain dengan debouncer. Ini cocok untuk dibuat menjadi dekorator / fungsi tingkat tinggi:
sumber
Sekarang ada solusi lain untuk Bereaksi dan Bereaksi Asli pada akhir / 2019 :
bereaksi-debounce-komponen
Ini adalah komponen, mudah digunakan, mungil dan didukung widley
Contoh:
* Saya pencipta komponen ini
sumber
Saya sedang mencari solusi untuk masalah yang sama dan menemukan utas ini serta beberapa yang lain tetapi mereka memiliki masalah yang sama: jika Anda mencoba untuk melakukan
handleOnChange
fungsi dan Anda membutuhkan nilai dari target acara, Anda akan mendapatkancannot read property value of null
atau kesalahan seperti itu. Dalam kasus saya, saya juga perlu menjaga konteksthis
di dalam fungsi debouncing karena saya sedang melakukan tindakan fluxible. Inilah solusi saya, ini berfungsi dengan baik untuk kasus penggunaan saya jadi saya meninggalkannya di sini kalau-kalau ada yang datang di utas ini:sumber
untuk
throttle
ataudebounce
cara terbaik adalah membuat pencipta fungsi sehingga Anda dapat menggunakannya di mana saja, misalnya:dan dalam
render
metode Anda, Anda dapat melakukan:yang
updateUserProfileField
metode akan membuat fungsi terpisah setiap kali Anda menyebutnya.Catatan jangan coba mengembalikan pawang secara langsung karena ini tidak akan berfungsi:
alasan mengapa ini tidak akan berhasil karena ini akan menghasilkan fungsi throttle baru setiap kali acara dipanggil alih-alih menggunakan fungsi throttle yang sama, jadi pada dasarnya throttle tidak akan berguna;)
Juga jika Anda menggunakan
debounce
atauthrottle
tidak perlusetTimeout
atauclearTimeout
, inilah sebabnya kami menggunakannya: Psumber
Berikut cuplikan menggunakan pendekatan @ Abra yang dibungkus dengan komponen fungsi (kami menggunakan fabric untuk UI, cukup ganti dengan tombol sederhana)
sumber
Solusi saya adalah berbasis kait (ditulis dalam naskah).
Saya punya 2 kait utama
useDebouncedValue
danuseDebouncedCallback
Pertama -
useDebouncedValue
Katakanlah kita memiliki kotak pencarian, tetapi kami ingin meminta server untuk hasil pencarian setelah pengguna berhenti mengetik 0,5s
Penerapan
Kedua
useDebouncedCallback
Itu hanya menciptakan fungsi 'terbebas' dalam lingkup komponen Anda.
Katakanlah kita memiliki komponen dengan tombol yang akan menampilkan peringatan 500 ms setelah Anda berhenti mengkliknya.
Implementasi (perhatikan saya menggunakan lodash / debounce sebagai pembantu)
sumber
Berikut adalah contoh TypeScript yang berfungsi untuk mereka yang menggunakan TS dan ingin mendebo
async
fungsi.sumber
sedikit terlambat di sini tetapi ini akan membantu. buat kelas ini (ditulis dalam naskah tetapi mudah dikonversi ke javascript)
dan untuk digunakan
sumber
Anda dapat menggunakan tlence tlence
sumber
Solusi Julen agak sulit dibaca, inilah kode reaksi yang lebih jelas dan to-the-point untuk siapa saja yang membuatnya tersandung berdasarkan judul dan bukan detail kecil dari pertanyaan.
tl; dr version : saat Anda memperbarui ke pengamat, kirim panggilan metode jadwal dan sebaliknya akan memberi tahu pengamat (atau melakukan ajax, dll.)
Lengkapi jsfiddle dengan contoh komponen jsfiddle
sumber
Hindari penggunaan
event.persist()
- Anda ingin membiarkan React mendaur ulang acara sintetis. Saya pikir cara terbersih apakah Anda menggunakan kelas atau kait adalah dengan membagi callback menjadi dua bagian:Kelas
Fungsi
Perhatikan bahwa jika
handleMouseOver
fungsi Anda menggunakan status dari dalam komponen, Anda harus menggunakanuseMemo
alih-alihuseRef
dan meneruskannya sebagai dependensi jika tidak, Anda akan bekerja dengan data basi (tidak berlaku untuk kelas saja).sumber
Perpanjang useState hook
Gunakan kait
https://trippingoncode.com/react-debounce-hook/
sumber
Ketemu masalah ini hari ini. Memecahkannya menggunakan
setTimeout
danclearTimeout
.Saya akan memberikan contoh bahwa Anda bisa beradaptasi:
Anda juga bisa melakukan refactor pada komponen fungsinya sendiri:
Dan gunakan seperti:
sumber