Bagaimana cara mereset komponen react termasuk semua status yang dapat dijangkau secara transitif?

94

Saya kadang-kadang bereaksi komponen yang secara konseptual stateful yang ingin saya setel ulang. Perilaku ideal akan sama dengan menghapus komponen lama dan membaca komponen baru yang asli.

React menyediakan metode setStateyang memungkinkan pengaturan status eksplisit komponen, tetapi tidak termasuk status implisit seperti fokus browser dan status formulir, dan juga mengecualikan status turunannya. Menangkap semua keadaan tidak langsung itu bisa menjadi tugas yang rumit, dan saya lebih suka menyelesaikannya dengan teliti dan menyeluruh daripada bermain-main dengan setiap bagian baru yang mengejutkan.

Apakah ada API atau pola untuk melakukan ini?

Sunting: Saya membuat contoh sepele yang mendemonstrasikan this.replaceState(this.getInitialState())pendekatan dan membandingkannya dengan this.setState(this.getInitialState())pendekatan: jsfiddle - replaceStatelebih kuat.

Eamon Nerbonne
sumber

Jawaban:

211

Untuk memastikan bahwa status browser implisit yang Anda sebutkan dan status turunan disetel ulang, Anda bisa menambahkan keyatribut ke komponen level root yang dikembalikan oleh render; ketika berubah, komponen itu akan dibuang dan dibuat dari awal.

render: function() {
    // ...
    return <div key={uniqueId}>
        {children}
    </div>;
}

Tidak ada jalan pintas untuk mengatur ulang status lokal setiap komponen.

Sophie Alpert
sumber
1
Hanya karena ingin tahu ketika Anda mengatakan 'komponen akan dibuang dan dibuat dari awal' maksud Anda DOM virtual akan dibuang dan dibuat dari awal tetapi pembaruan DOM akan tetap terjadi berdasarkan algoritme diff?
nimgrg
1
@nimgrg Tidak, elemen DOM asli juga akan dibuat ulang. (DOM virtual sudah dibuat ulang pada setiap render jadi jika Anda ingin mempertahankan DOM asli, cukup jangan setel a keydalam kasus ini.)
Sophie Alpert
3
@EamonNerbonne Pada React 0.8, kunci hanya digunakan untuk membedakan antara elemen saudara dalam sebuah array dan diabaikan di root. Lihat github.com/facebook/react/issues/590 .
Sophie Alpert
Note replaceState()dan getInitialState()keduanya tidak digunakan lagi dalam reactjs gaya kelas ES6 yang baru. Gunakan this.setState(this._getInitialState())sebagai gantinya. Anda juga tidak dapat menamai fungsi penginisialisasi status Anda sendiri getInitialState()- react melempar peringatan - menyebutnya hal lain dan secara eksplisit dilakukan state = this._getInitialState()di tingkat atas kelas.
thom_nic
2
Apakah ada cara untuk melakukan ini dari bagian dalam komponen tanpa memerlukan bagian luar untuk melewatkan penyangga kunci?
trusktr
14

Anda harus benar-benar menghindari replaceStatedan menggunakan setStatesebagai gantinya.

Dokumen mengatakan bahwa replaceState"mungkin dihapus seluruhnya dalam versi React yang akan datang." Saya pikir itu pasti akan dihapus karena replaceStatetidak benar-benar sesuai dengan filosofi React. Ini memfasilitasi pembuatan komponen React mulai terasa seperti pisau swiss-y. Ini menghalangi pertumbuhan alami komponen React yang menjadi lebih kecil, dan lebih dibuat khusus.

Di React, jika Anda harus melakukan kesalahan pada generalisasi atau spesialisasi: bidiklah spesialisasi. Sebagai akibatnya, pohon status untuk komponen Anda harus memiliki kesederhanaan tertentu (tidak masalah untuk melanggar aturan ini dengan selera tinggi jika Anda merancang produk baru yang sangat bagus).

Bagaimanapun ini adalah bagaimana Anda melakukannya. Mirip dengan jawaban Ben (diterima) di atas, tetapi seperti ini:

this.setState(this.getInitialState());

Juga (seperti yang dikatakan Ben) untuk mengatur ulang "status browser" Anda perlu menghapus simpul DOM itu. Manfaatkan kekuatan vdom dan gunakan keyprop baru untuk komponen itu. Render baru akan menggantikan grosir komponen itu.

Referensi: https://facebook.github.io/react/docs/component-api.html#replacestate

wle8300.dll
sumber
2
Ini tidak akan berfungsi jika status saat ini menyertakan properti apa pun yang tidak dalam status awal. Meskipun saya tidak percaya itu adalah "keadaan" yang hebat, kecuali Anda dapat mencegahnya, saya ingin menghindari kerusakan yang mengejutkan. Saya akan baik-baik saja dengan reset yang macet dalam beberapa kasus, tetapi bukan reset yang secara halus merusak status.
Eamon Nerbonne
Tidak yakin saya ikuti. Apakah Anda mengatakan ini tidak sama dengan this.replaceState? Karena itu.
wle8300
1
@ williamle8300 Mereka tidak akan setara jika properti baru ditambahkan ke status di suatu tempat dalam siklus hidup komponen antara panggilan ke getInitialState()(misalnya, dalam handler onClick). Dalam hal ini, properti baru tersebut akan tetap ada setelah tanggal 2 getInitialState().
Graham
@Graham Saya yakin itu praktik yang buruk untuk memperkenalkan status baru ke komponen yang belum dideklarasikan getInitialState. Mirip seperti mendeklarasikan semua variabel Anda dalam Fungsi JS di bagian atas fungsi. Catatan tambahan: Solusi Ben Alpert hampir sama dengan solusi saya ... dan dia adalah pengelola React resmi!
wle8300
1
Saya khawatir fungsi getInitialState (), dan karenanya jawabannya, tidak digunakan lagi. Pembaruan akan menyenangkan.
Martin R.
10

Menambahkan keyatribut ke elemen yang Anda perlukan untuk menginisialisasi ulang, akan memuatnya kembali setiap kali propsatau stateterkait dengan perubahan elemen.

kunci = {Tanggal baru (). getTime ()}

Berikut ini contohnya:

render() {
  const items = (this.props.resources) || [];
  const totalNumberOfItems = (this.props.resources.noOfItems) || 0;

  return (
    <div className="items-container">
      <PaginationContainer
        key={new Date().getTime()}
        totalNumberOfItems={totalNumberOfItems}
        items={items}
        onPageChange={this.onPageChange}
      />
    </div>
  );
}
jsbisht.dll
sumber
1
Atau Anda dapat menambahkan variabel penghitung integer sederhana sebagai kunci
minimalis