Apakah menggunakan componentDidMount()
sebagai fungsi async praktik yang baik dalam Bereaksi Asli atau haruskah saya menghindarinya?
Saya perlu mendapatkan beberapa info dari AsyncStorage
saat komponen mount, tetapi satu-satunya cara saya tahu untuk membuat itu mungkin adalah membuat componentDidMount()
fungsi async.
async componentDidMount() {
let auth = await this.getAuth();
if (auth)
this.checkAuth(auth);
}
Apakah ada masalah dengan itu dan apakah ada solusi lain untuk masalah ini?
reactjs
asynchronous
react-native
Mirakurun
sumber
sumber
Jawaban:
Mari kita mulai dengan menunjukkan perbedaan dan menentukan bagaimana hal itu dapat menyebabkan masalah.
Berikut adalah kode
componentDidMount()
metode siklus hidup async dan "sync" :Dengan melihat kode, saya dapat menunjukkan perbedaan berikut:
async
kunci: Dalam naskah, ini hanyalah penanda kode. Itu melakukan 2 hal:Promise<void>
bukanvoid
. Jika Anda secara eksplisit menentukan jenis pengembalian yang tidak menjanjikan (mis: kosong), naskah akan meludahi kesalahan Anda.await
kata kunci di dalam metode.void
menjadiPromise<void>
async someMethod(): Promise<void> { await componentDidMount(); }
Anda sekarang dapat menggunakan
await
kata kunci di dalam metode dan untuk sementara menghentikan eksekusi. Seperti ini:Sekarang, bagaimana mereka dapat menyebabkan masalah?
async
kunci tersebut sama sekali tidak berbahaya.Saya tidak dapat membayangkan situasi apa pun di mana Anda perlu melakukan panggilan ke
componentDidMount()
metode ini sehingga jenis pengembaliannyaPromise<void>
juga tidak berbahaya.Memanggil ke metode yang memiliki jenis pengembalian
Promise<void>
tanpaawait
kata kunci tidak akan membuat perbedaan dengan memanggil satu dengan jenis kembalivoid
.Karena tidak ada metode siklus hidup setelah
componentDidMount()
menunda pelaksanaannya tampaknya cukup aman. Tetapi ada gotcha.Katakanlah, di atas
this.setState({users, questions});
akan dieksekusi setelah 10 detik. Di tengah waktu tunda, yang lain ...this.setState({users: newerUsers, questions: newerQuestions});
... berhasil dieksekusi dan DOM dimutakhirkan. Hasilnya terlihat oleh pengguna. Jam terus berdetak dan 10 detik berlalu. Yang tertunda
this.setState(...)
kemudian akan dijalankan dan DOM akan diperbarui lagi, waktu itu dengan pengguna lama dan pertanyaan lama. Hasilnya juga akan terlihat oleh pengguna.=> Cukup aman (saya tidak yakin 100%) untuk digunakan
async
dengancomponentDidMount()
metode. Saya penggemar beratnya dan sejauh ini saya belum menemukan masalah yang membuat saya sakit kepala terlalu banyak.sumber
setState()
selalu memiliki risiko kecil. Kita harus melanjutkan dengan hati-hati.isFetching: true
di dalam keadaan komponen. Saya hanya menggunakan ini dengan redux tapi saya kira itu benar-benar valid dengan manajemen keadaan hanya reaksi. Meskipun itu tidak benar-benar menyelesaikan masalah keadaan yang sama diperbarui di tempat lain dalam kode ...isFetching
solusi flag cukup umum terutama ketika kita ingin memainkan beberapa animasi di front-end sambil menunggu respon back-end (isFetching: true
).Pembaruan April 2020: Masalah ini tampaknya telah diperbaiki pada React 16.13.1 terbaru, lihat contoh kotak pasir ini . Terima kasih kepada @abernier karena telah menunjukkan ini.
Saya telah melakukan beberapa penelitian, dan saya telah menemukan satu perbedaan penting: Bereaksi tidak memproses kesalahan dari metode siklus hidup async.
Jadi, jika Anda menulis sesuatu seperti ini:
maka kesalahan Anda akan ditangkap oleh batas kesalahan , dan Anda dapat memprosesnya dan menampilkan pesan yang anggun.
Jika kita mengubah kode seperti ini:
yang setara dengan ini:
maka kesalahan Anda akan ditelan diam-diam . Malu pada Anda, Bereaksi ...
Jadi, bagaimana kita memproses kesalahan daripada? Satu-satunya cara tampaknya menjadi tangkapan eksplisit seperti ini:
atau seperti ini:
Jika kita masih ingin kesalahan kita mencapai batas kesalahan, saya dapat memikirkan trik berikut:
render
metodeContoh:
sumber
Kode Anda baik dan sangat mudah dibaca oleh saya. Lihat artikel Dale Jefferson ini di mana ia menunjukkan
componentDidMount
contoh async dan terlihat sangat bagus juga.Tetapi beberapa orang akan mengatakan bahwa seseorang yang membaca kode dapat berasumsi bahwa Bereaksi melakukan sesuatu dengan janji yang dikembalikan.
Jadi interpretasi kode ini dan apakah itu praktik yang baik atau tidak, sangat pribadi.
Jika Anda menginginkan solusi lain, Anda bisa menggunakan janji . Sebagai contoh:
sumber
async
fungsi sebaris denganawait
s di dalam ...?(async () => { const data = await fetch('foo'); const result = await submitRequest({data}); console.log(result) })()
manafetch
dansubmitRequest
adalah fungsi yang mengembalikan janji.Ketika Anda menggunakan
componentDidMount
tanpaasync
kata kunci, dokter mengatakan ini:Jika Anda menggunakan
async componentDidMount
Anda akan kehilangan kemampuan ini: render lain akan terjadi SETELAH browser memperbarui layar. Tetapi saya juga, jika Anda berpikir untuk menggunakan async, seperti mengambil data, Anda tidak dapat menghindari browser akan memperbarui layar dua kali. Di dunia lain, PAUSE componentDidMount tidak dimungkinkan sebelum browser memperbarui layarsumber
Memperbarui:
(Bangun saya: React 16, Webpack 4, Babel 7):
Saat menggunakan Babel 7 Anda akan menemukan:
Menggunakan pola ini ...
Anda akan mengalami kesalahan berikut ...
ReferenceError Uncaught: regeneratorRuntime tidak didefinisikan
Dalam hal ini Anda perlu menginstal babel-plugin-transform-runtime
https://babeljs.io/docs/en/babel-plugin-transform-runtime.html
Jika karena alasan tertentu Anda tidak ingin menginstal paket di atas (babel-plugin-transform-runtime) maka Anda ingin tetap berpegang pada pola Janji ...
sumber
Saya pikir itu baik-baik saja selama Anda tahu apa yang Anda lakukan. Tapi itu bisa membingungkan karena
async componentDidMount()
masih bisa berjalan setelahcomponentWillUnmount
dijalankan dan komponen telah dilepas.Anda mungkin juga ingin memulai tugas sinkron dan asinkron di dalam
componentDidMount
. JikacomponentDidMount
async, Anda harus meletakkan semua kode sinkron sebelum yang pertamaawait
. Mungkin tidak jelas bagi seseorang bahwa kode sebelum yang pertamaawait
berjalan secara sinkron. Dalam hal ini, saya mungkin akan tetapcomponentDidMount
sinkron tetapi minta metode sinkronisasi dan async.Apakah Anda memilih
async componentDidMount()
vs metodecomponentDidMount()
panggilan sinkronisasiasync
, Anda harus memastikan Anda membersihkan setiap pendengar atau metode async yang mungkin masih berjalan ketika komponen dilepas.sumber
Sebenarnya, memuat async di ComponentDidMount adalah pola desain yang disarankan karena Bereaksi menjauh dari metode siklus hidup sebelumnya (componentWillMount, componentWillReceiveProps, componentWillUpdate) dan selanjutnya ke Render Async.
Posting blog ini sangat membantu dalam menjelaskan mengapa ini aman dan memberikan contoh untuk memuat async di ComponentDidMount:
https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
sumber
Saya suka menggunakan sesuatu seperti ini
sumber