Saya memiliki tindakan yang memperbarui status pemberitahuan aplikasi saya. Biasanya, pemberitahuan ini akan menjadi semacam kesalahan atau info. Saya perlu mengirim tindakan lain setelah 5 detik yang akan mengembalikan status pemberitahuan ke yang awal, jadi tidak ada pemberitahuan. Alasan utama di balik ini adalah untuk menyediakan fungsionalitas di mana notifikasi menghilang secara otomatis setelah 5 detik.
Saya tidak beruntung menggunakan setTimeout
dan mengembalikan tindakan lain dan tidak dapat menemukan bagaimana ini dilakukan secara online. Jadi saran apa pun dipersilahkan.
redux-saga
jawaban berdasarkan saya jika Anda menginginkan sesuatu yang lebih baik daripada thunks. Terlambat menjawab sehingga Anda harus menggulir waktu yang lama sebelum melihatnya :) tidak berarti itu tidak layak dibaca. Berikut ini jalan pintas: stackoverflow.com/a/38574266/82609Jawaban:
Jangan terjebak dalam pemikiran bahwa perpustakaan harus meresepkan cara melakukan segalanya . Jika Anda ingin melakukan sesuatu dengan batas waktu dalam JavaScript, Anda perlu menggunakannya
setTimeout
. Tidak ada alasan mengapa tindakan Redux harus berbeda.Redux memang menawarkan beberapa cara alternatif untuk menangani hal-hal yang tidak sinkron, tetapi Anda hanya boleh menggunakannya ketika Anda menyadari Anda mengulangi terlalu banyak kode. Kecuali Anda memiliki masalah ini, gunakan apa yang ditawarkan bahasa dan gunakan solusi paling sederhana.
Menulis Async Code Inline
Sejauh ini, ini adalah cara paling sederhana. Dan tidak ada yang spesifik untuk Redux di sini.
Demikian pula, dari dalam komponen yang terhubung:
Satu-satunya perbedaan adalah bahwa dalam komponen yang terhubung Anda biasanya tidak memiliki akses ke toko itu sendiri, tetapi mendapatkan salah satu
dispatch()
atau pembuat tindakan tertentu disuntikkan sebagai alat peraga. Namun ini tidak ada bedanya bagi kami.Jika Anda tidak suka membuat kesalahan ketik saat mengirim tindakan yang sama dari komponen yang berbeda, Anda mungkin ingin mengekstrak pembuat tindakan alih-alih mengirimkan objek tindakan secara inline:
Atau, jika sebelumnya Anda telah mengikatnya dengan
connect()
:Sejauh ini kami belum menggunakan middleware atau konsep canggih lainnya.
Mengekstrak Pencipta Tindakan Async
Pendekatan di atas berfungsi dengan baik dalam kasus-kasus sederhana tetapi Anda mungkin menemukan bahwa ia memiliki beberapa masalah:
HIDE_NOTIFICATION
, menyembunyikan pemberitahuan kedua lebih cepat daripada setelah batas waktu.Untuk mengatasi masalah ini, Anda perlu mengekstrak fungsi yang memusatkan logika batas waktu dan mengirimkan dua tindakan tersebut. Mungkin terlihat seperti ini:
Sekarang komponen dapat digunakan
showNotificationWithTimeout
tanpa menduplikasi logika ini atau memiliki kondisi balapan dengan pemberitahuan berbeda:Mengapa
showNotificationWithTimeout()
menerimadispatch
sebagai argumen pertama? Karena itu perlu mengirimkan tindakan ke toko. Biasanya komponen memiliki akses kedispatch
tetapi karena kita ingin fungsi eksternal untuk mengambil kendali atas pengiriman, kita perlu memberikannya kontrol atas pengiriman.Jika Anda memiliki toko tunggal yang diekspor dari beberapa modul, Anda bisa mengimpornya dan
dispatch
langsung menggunakannya:Ini terlihat lebih sederhana tetapi kami tidak merekomendasikan pendekatan ini . Alasan utama kami tidak suka itu adalah karena itu memaksa toko untuk menjadi lajang . Ini membuatnya sangat sulit untuk mengimplementasikan rendering server . Di server, Anda ingin setiap permintaan memiliki toko sendiri, sehingga pengguna yang berbeda mendapatkan data yang dimuat sebelumnya berbeda.
Toko tunggal juga membuat pengujian lebih sulit. Anda tidak lagi dapat mengejek toko ketika menguji pembuat tindakan karena mereka merujuk toko nyata tertentu yang diekspor dari modul tertentu. Anda bahkan tidak dapat mengatur ulang keadaannya dari luar.
Jadi, sementara Anda secara teknis dapat mengekspor toko tunggal dari modul, kami tidak mendukungnya. Jangan lakukan ini kecuali Anda yakin bahwa aplikasi Anda tidak akan pernah menambahkan rendering server.
Kembali ke versi sebelumnya:
Ini menyelesaikan masalah dengan duplikasi logika dan menyelamatkan kita dari kondisi balapan.
Thlk Middleware
Untuk aplikasi sederhana, pendekatannya sudah cukup. Jangan khawatir tentang middleware jika Anda senang.
Namun, dalam aplikasi yang lebih besar, Anda mungkin menemukan ketidaknyamanan tertentu di sekitarnya.
Sebagai contoh, sangat disayangkan kita harus berpapasan
dispatch
. Ini membuatnya lebih sulit untuk memisahkan wadah dan komponen presentasi karena setiap komponen yang mengirim tindakan Redux secara tidak sinkron dengan cara di atas harus diterimadispatch
sebagai penyangga agar dapat meneruskannya lebih lanjut. Anda tidak dapat lagi mengikat pembuat tindakan denganconnect()
karenashowNotificationWithTimeout()
tidak benar-benar pembuat tindakan. Itu tidak mengembalikan tindakan Redux.Selain itu, mungkin aneh untuk mengingat fungsi mana yang merupakan pembuat tindakan sinkron seperti
showNotification()
dan yang merupakan pembantu asinkronshowNotificationWithTimeout()
. Anda harus menggunakannya secara berbeda dan berhati-hati agar tidak salah mengartikannya.Ini adalah motivasi untuk menemukan cara untuk "melegitimasi" pola penyediaan
dispatch
fungsi pembantu ini, dan membantu Redux "melihat" seperti pembuat tindakan sinkron sebagai kasus khusus pembuat tindakan normal daripada fungsi yang sama sekali berbeda.Jika Anda masih bersama kami dan Anda juga mengenali sebagai masalah di aplikasi Anda, Anda dipersilakan untuk menggunakan middleware Redux Thunk .
Dalam intinya, Redux Thunk mengajarkan Redux untuk mengenali jenis tindakan khusus yang sebenarnya berfungsi:
Ketika middleware ini diaktifkan, jika Anda mengirim suatu fungsi , middleware Redux Thunk akan memberikannya
dispatch
sebagai argumen. Ini juga akan "menelan" tindakan seperti itu jadi jangan khawatir tentang reduksi Anda menerima argumen fungsi aneh. Pereduksi Anda hanya akan menerima tindakan objek biasa - baik dipancarkan secara langsung, atau dipancarkan oleh fungsi seperti yang baru saja kami jelaskan.Ini tidak terlihat sangat berguna, bukan? Tidak dalam situasi khusus ini. Namun itu memungkinkan kami mendeklarasikan
showNotificationWithTimeout()
sebagai pembuat tindakan Redux biasa:Perhatikan bagaimana fungsinya hampir identik dengan yang kita tulis di bagian sebelumnya. Namun itu tidak diterima
dispatch
sebagai argumen pertama. Alih-alih mengembalikan fungsi yang menerimadispatch
sebagai argumen pertama.Bagaimana kita menggunakannya dalam komponen kita? Jelas, kita bisa menulis ini:
Kami memanggil pembuat tindakan async untuk mendapatkan fungsi batin yang hanya ingin
dispatch
, dan kemudian kami lulusdispatch
.Namun ini bahkan lebih aneh daripada versi aslinya! Mengapa kita bahkan pergi ke sana?
Karena apa yang saya katakan sebelumnya. Jika Redux Thunk middleware diaktifkan, setiap kali Anda mencoba mengirim fungsi alih-alih objek tindakan, middleware akan memanggil fungsi itu dengan
dispatch
metode itu sendiri sebagai argumen pertama .Jadi kita bisa melakukan ini sebagai gantinya:
Akhirnya, mengirimkan tindakan asinkron (sebenarnya, serangkaian tindakan) terlihat tidak berbeda dengan mengirimkan satu tindakan secara sinkron ke komponen. Yang bagus karena komponen tidak boleh peduli apakah sesuatu terjadi secara sinkron atau asinkron. Kami baru saja mengabstraksikan hal itu.
Perhatikan bahwa karena kita “diajarkan” Redux untuk mengenali pencipta tindakan “khusus” seperti (kami menyebutnya dunk pencipta tindakan), kita sekarang dapat menggunakannya di mana saja di mana kita akan menggunakan pencipta tindakan biasa. Sebagai contoh, kita dapat menggunakannya dengan
connect()
:Status Membaca dalam Thunks
Biasanya reduksi Anda mengandung logika bisnis untuk menentukan status berikutnya. Namun, reduksi hanya masuk setelah tindakan dikirim. Bagaimana jika Anda memiliki efek samping (seperti memanggil API) di pembuat tindakan thunk, dan Anda ingin mencegahnya dalam kondisi tertentu?
Tanpa menggunakan middleware thunk, Anda cukup melakukan pemeriksaan di dalam komponen:
Namun, tujuan mengekstraksi pembuat tindakan adalah memusatkan logika berulang ini di banyak komponen. Untungnya, Redux Thunk menawarkan Anda cara untuk membaca keadaan toko Redux saat ini. Selain itu
dispatch
,getState
argumen ini juga berfungsi sebagai argumen kedua untuk fungsi yang Anda kembali dari pembuat tindakan thunk Anda. Ini memungkinkan thunk membaca keadaan toko saat ini.Jangan menyalahgunakan pola ini. Ini bagus untuk membatalkan panggilan API ketika ada data yang di-cache tersedia, tetapi itu bukan fondasi yang sangat baik untuk membangun logika bisnis Anda. Jika Anda
getState()
hanya menggunakan untuk mengirim tindakan yang berbeda secara kondisional, pertimbangkan untuk memasukkan logika bisnis ke dalam reduksi.Langkah selanjutnya
Sekarang setelah Anda memiliki intuisi dasar tentang cara kerja thunks, lihat contoh Redux async yang menggunakannya.
Anda dapat menemukan banyak contoh di mana thunks mengembalikan Janji. Ini tidak diperlukan tetapi bisa sangat nyaman. Redux tidak peduli apa yang Anda kembali dari thunk, tetapi itu memberi Anda nilai pengembaliannya
dispatch()
. Inilah sebabnya mengapa Anda dapat mengembalikan Janji dari seorang pencuri dan menunggu sampai selesai dengan menelepondispatch(someThunkReturningPromise()).then(...)
.Anda juga dapat membagi pembuat tindakan thunk yang kompleks menjadi beberapa pembuat aksi thunk yang lebih kecil. The
dispatch
Metode yang disediakan oleh thunks dapat menerima thunks sendiri, sehingga Anda dapat menerapkan pola rekursif. Sekali lagi, ini bekerja paling baik dengan Janji karena Anda dapat menerapkan aliran kontrol asinkron di atas semua itu.Untuk beberapa aplikasi, Anda mungkin menemukan diri Anda dalam situasi di mana persyaratan aliran kontrol asinkron Anda terlalu rumit untuk diungkapkan dengan thunks. Misalnya, mencoba ulang permintaan yang gagal, aliran otorisasi ulang dengan token, atau onboarding langkah-demi-langkah bisa terlalu bertele-tele dan rawan kesalahan saat ditulis dengan cara ini. Dalam hal ini, Anda mungkin ingin melihat solusi aliran kontrol asinkron yang lebih canggih seperti Redux Saga atau Redux Loop . Evaluasi mereka, bandingkan contoh yang relevan dengan kebutuhan Anda, dan pilih yang paling Anda sukai.
Akhirnya, jangan gunakan apa pun (termasuk thunks) jika Anda tidak benar-benar membutuhkannya. Ingat bahwa, tergantung pada persyaratan, solusi Anda mungkin terlihat sesederhana itu
Jangan berkeringat kecuali Anda tahu mengapa Anda melakukan ini.
sumber
if (cond) dispatch({ type: 'A' }) else dispatch({ type: 'B' })
mungkin Anda harus adildispatch({ type: 'C', something: cond })
dan memilih untuk mengabaikan tindakan dalam reduksi, tergantung padaaction.something
dan kondisi saat ini.Menggunakan Redux-saga
Seperti yang dikatakan Dan Abramov, jika Anda ingin kontrol lebih lanjut atas kode async Anda, Anda mungkin melihat redux-saga .
Jawaban ini adalah contoh sederhana, jika Anda ingin penjelasan yang lebih baik tentang mengapa redux-saga dapat berguna untuk aplikasi Anda, periksa jawaban lain ini .
Gagasan umum adalah bahwa Redux-saga menawarkan interpreter generator ES6 yang memungkinkan Anda untuk dengan mudah menulis kode async yang terlihat seperti kode sinkron (ini sebabnya Anda akan sering menemukan infinite saat loop di Redux-saga). Entah bagaimana, Redux-saga sedang membangun bahasanya sendiri langsung di dalam Javascript. Redux-saga dapat terasa agak sulit untuk dipelajari pada awalnya, karena Anda membutuhkan pemahaman dasar generator, tetapi juga memahami bahasa yang ditawarkan oleh Redux-saga.
Saya akan mencoba di sini untuk menjelaskan di sini sistem pemberitahuan yang saya buat di atas redux-saga. Contoh ini saat ini berjalan dalam produksi.
Spesifikasi sistem pemberitahuan lanjut
Hasil
Cuplikan layar aplikasi produksi saya Stample.co
Kode
Di sini saya menamai notifikasi
toast
tetapi ini adalah detail penamaan.Dan peredamnya:
Pemakaian
Anda cukup mengirimkan
TOAST_DISPLAY_REQUESTED
acara. Jika Anda mengirim 4 permintaan, hanya 3 pemberitahuan yang akan ditampilkan, dan yang 4 akan muncul sedikit kemudian setelah pemberitahuan 1 menghilang.Perhatikan bahwa saya tidak secara khusus merekomendasikan pengiriman
TOAST_DISPLAY_REQUESTED
dari BEJ. Anda lebih suka menambahkan kisah lain yang mendengarkan acara aplikasi yang sudah ada, dan kemudian mengirimkanTOAST_DISPLAY_REQUESTED
: komponen Anda yang memicu notifikasi, tidak harus digabungkan dengan erat ke sistem notifikasi.Kesimpulan
Kode saya tidak sempurna tetapi berjalan dalam produksi dengan 0 bug selama berbulan-bulan. Redux-saga dan generator pada awalnya agak sulit, tetapi begitu Anda memahaminya, sistem semacam ini cukup mudah dibangun.
Bahkan cukup mudah untuk menerapkan aturan yang lebih kompleks, seperti:
Honnestly, semoga sukses menerapkan hal-hal seperti ini dengan benar pada thunks
Catatan Anda dapat melakukan hal yang persis sama dengan redux-observable yang sangat mirip dengan redux-saga. Itu hampir sama dan merupakan masalah selera antara generator dan RxJS.
sumber
yield call(delay,timeoutValue);
: itu bukan API yang sama tetapi memiliki efek yang samaRepositori dengan proyek sampel
Saat ini ada empat proyek sampel:
Jawaban yang diterima luar biasa.
Tetapi ada sesuatu yang hilang:
Jadi saya membuat repositori Hello Async untuk menambahkan hal-hal yang hilang:
Redux Saga
Jawaban yang diterima sudah menyediakan cuplikan kode sampel untuk Async Code Inline, Async Action Generator dan Redux Thunk. Demi kelengkapan, saya memberikan cuplikan kode untuk Redux Saga:
Tindakannya sederhana dan murni.
Tidak ada yang spesial dengan komponen.
Sagas didasarkan pada Generator ES6
Dibandingkan dengan Redux Thunk
Pro
Cons
Silakan merujuk ke proyek runnable jika potongan kode di atas tidak menjawab semua pertanyaan Anda.
sumber
Anda dapat melakukan ini dengan redux-thunk . Ada panduan dalam dokumen redux untuk tindakan async seperti setTimeout.
sumber
applyMiddleware(ReduxPromise, thunk)(createStore)
inilah cara Anda menambahkan beberapa middleware (koma terpisah?) Karena sepertinya saya tidak dapat mengaktifkan thunk.const store = createStore(reducer, applyMiddleware([ReduxPromise, thunk]));
Saya akan merekomendasikan juga melihat pola SAM .
Pola SAM menganjurkan untuk memasukkan "next-action-predicate" di mana tindakan (otomatis) seperti "pemberitahuan menghilang secara otomatis setelah 5 detik" dipicu setelah model telah diperbarui (model SAM ~ keadaan peredam + toko +).
Pola menganjurkan untuk mengurutkan tindakan dan mutasi model satu per satu, karena "status kontrol" dari model "mengontrol" tindakan mana yang diaktifkan dan / atau secara otomatis dieksekusi oleh predikat aksi berikutnya. Anda tidak bisa memprediksi (secara umum) keadaan apa sistem akan sebelum memproses suatu tindakan dan karenanya apakah tindakan Anda selanjutnya diharapkan akan diizinkan / mungkin.
Jadi misalnya kodenya,
tidak akan diizinkan dengan SAM, karena fakta bahwa tindakan hideNotification dapat dikirim tergantung pada model yang berhasil menerima nilai "showNotication: true". Mungkin ada bagian lain dari model yang mencegahnya menerimanya dan oleh karena itu, tidak ada alasan untuk memicu tindakan hideNotification.
Saya akan sangat menyarankan agar menerapkan predikat tindakan selanjutnya yang tepat setelah pembaruan toko dan status kontrol baru model dapat diketahui. Itu cara teraman untuk menerapkan perilaku yang Anda cari.
Anda dapat bergabung dengan kami di Gitter jika Anda mau. Ada juga panduan memulai SAM yang tersedia di sini .
sumber
V = S( vm( M.present( A(data) ) ), nap(M))
itu indah. Terima kasih telah berbagi pemikiran dan pengalaman Anda. Saya akan menggali lebih dalam.Setelah mencoba berbagai pendekatan populer (pembuat aksi, thunks, saga, epos, efek, custom middleware), saya masih merasa mungkin ada ruang untuk perbaikan sehingga saya mendokumentasikan perjalanan saya di artikel blog ini, Di mana saya menempatkan logika bisnis saya di aplikasi Bereaksi / Redux?
Sama seperti diskusi di sini, saya mencoba kontras dan membandingkan berbagai pendekatan. Akhirnya itu membuat saya memperkenalkan perpustakaan redux-logic baru yang mengambil inspirasi dari epos, sagas, custom middleware.
Ini memungkinkan Anda untuk mencegat tindakan untuk memvalidasi, memverifikasi, mengotorisasi, serta menyediakan cara untuk melakukan async IO.
Beberapa fungsi umum hanya dapat dideklarasikan seperti debouncing, pelambatan, pembatalan, dan hanya menggunakan respons dari permintaan terbaru (takeLatest). redux-logic membungkus kode Anda menyediakan fungsionalitas ini untuk Anda.
Itu membebaskan Anda untuk mengimplementasikan logika bisnis inti Anda sesuka Anda. Anda tidak harus menggunakan observable atau generator kecuali Anda mau. Gunakan fungsi dan panggilan balik, janji, fungsi async (async / tunggu), dll.
Kode untuk melakukan notifikasi 5s sederhana adalah sesuatu seperti:
Saya memiliki contoh pemberitahuan yang lebih maju dalam repo saya yang berfungsi mirip dengan apa yang dijelaskan oleh Sebastian Lorber di mana Anda dapat membatasi tampilan hingga N item dan memutar melalui item yang antri. contoh pemberitahuan redux-logika
Saya punya berbagai contoh live redux-logic jsfiddle serta contoh lengkap . Saya terus bekerja pada dokumen dan contoh.
Saya ingin mendengar tanggapan Anda.
sumber
Saya mengerti bahwa pertanyaan ini agak lama tapi saya akan memperkenalkan solusi lain menggunakan redux-observable alias. Epik.
Mengutip dokumentasi resmi:
Apa yang bisa diamati-redux?
Epik adalah inti primitif yang dapat diamati kembali.
Dengan kata-kata yang lebih banyak atau lebih sedikit, Anda dapat membuat fungsi yang menerima tindakan melalui Stream dan kemudian mengembalikan aliran tindakan baru (menggunakan efek samping yang umum seperti timeout, penundaan, interval, dan permintaan).
Biarkan saya memposting kode dan kemudian menjelaskan sedikit tentangnya
store.js
index.js
App.js
Kode kunci untuk menyelesaikan masalah ini semudah pie seperti yang Anda lihat, satu-satunya hal yang tampak berbeda dari jawaban lainnya adalah fungsi rootEpic.
Butir 1. Seperti halnya saga, Anda harus menggabungkan epos untuk mendapatkan fungsi tingkat atas yang menerima aliran tindakan dan mengembalikan aliran tindakan, sehingga Anda dapat menggunakannya dengan pabrik middleware createEpicMiddleware . Dalam kasus kami, kami hanya perlu satu sehingga kami hanya memiliki rootEpic kami sehingga kami tidak harus menggabungkan apa pun, tetapi itu baik untuk mengetahui fakta.
Poin 2. RootEpic kami yang menangani logika efek samping hanya membutuhkan sekitar 5 baris kode yang luar biasa! Termasuk fakta yang cukup banyak deklaratif!
Butir 3. Penjelasan baris demi baris rootEpic (dalam komentar)
Saya harap ini membantu!
sumber
switchMap
?Kenapa harus begitu sulit? Itu hanya logika UI. Gunakan tindakan khusus untuk mengatur data notifikasi:
dan komponen khusus untuk menampilkannya:
Dalam hal ini pertanyaannya harus "bagaimana Anda membersihkan negara lama?", "Bagaimana cara memberitahu komponen bahwa waktu telah berubah"
Anda dapat menerapkan beberapa tindakan TIMEOUT yang dikirim pada setTimeout dari suatu komponen.
Mungkin tidak apa-apa untuk membersihkannya setiap kali pemberitahuan baru ditampilkan.
Lagi pula, harus ada
setTimeout
tempat, kan? Mengapa tidak melakukannya dalam suatu komponenMotivasinya adalah bahwa fungsi "notifikasi memudar" benar-benar menjadi perhatian UI. Jadi itu menyederhanakan pengujian untuk logika bisnis Anda.
Tampaknya tidak masuk akal untuk menguji bagaimana penerapannya. Masuk akal untuk memverifikasi kapan pemberitahuan akan habis. Dengan demikian lebih sedikit kode untuk rintisan, tes lebih cepat, kode pembersih.
sumber
Jika Anda ingin penanganan batas waktu pada tindakan selektif, Anda dapat mencoba pendekatan middleware . Saya menghadapi masalah serupa untuk menangani tindakan berdasarkan janji secara selektif dan solusi ini lebih fleksibel.
Katakanlah Anda pembuat tindakan Anda terlihat seperti ini:
batas waktu dapat menampung banyak nilai dalam tindakan di atas
Implementasi middleware Anda akan terlihat seperti ini:
Anda sekarang dapat merutekan semua tindakan Anda melalui lapisan middleware ini menggunakan redux.
Anda dapat menemukan beberapa contoh serupa di sini
sumber
Cara yang tepat untuk melakukan ini adalah menggunakan Redux Thunk yang merupakan middleware populer untuk Redux, sesuai dengan dokumentasi Redux Thunk:
Jadi pada dasarnya itu mengembalikan fungsi, dan Anda dapat menunda pengiriman Anda atau meletakkannya dalam kondisi kondisi.
Jadi sesuatu seperti ini akan melakukan pekerjaan untuk Anda:
sumber
Sederhana saja. Gunakan paket trim-redux dan tulis seperti ini di
componentDidMount
tempat lain dan bunuhcomponentWillUnmount
.sumber
Redux sendiri adalah pustaka verbose yang cantik, dan untuk hal-hal seperti itu Anda harus menggunakan sesuatu seperti Redux-thunk , yang akan memberikan
dispatch
fungsi, sehingga Anda dapat mengirim penutupan pemberitahuan setelah beberapa detik.Saya telah membuat perpustakaan untuk mengatasi masalah seperti verbositas dan kompabilitas, dan contoh Anda akan terlihat seperti berikut:
Jadi kami membuat tindakan sinkronisasi untuk menampilkan pemberitahuan di dalam tindakan async, yang dapat meminta beberapa info latar belakang, atau memeriksa nanti apakah pemberitahuan ditutup secara manual.
sumber