Gunakan status atau referensi dalam komponen formulir React.js?

116

Saya mulai dengan React.js dan saya ingin membuat formulir sederhana tetapi dalam dokumentasi saya telah menemukan dua cara untuk melakukannya.

Yang pertama menggunakan Referensi :

var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    // TODO: send request to the server
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
    return;
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

Dan yang kedua adalah menggunakan state di dalam komponen React:

var TodoTextInput = React.createClass({
  getInitialState: function() {
    return {
      value: this.props.value || ''
    };
  },

  render: function() /*object*/ {
    return (
      <input className={this.props.className}
      id={this.props.id}
      placeholder={this.props.placeholder}
      onBlur={this._save}
      value={this.state.value}
      />
    );
  },

  _save: function() {
    this.props.onSave(this.state.value);
    this.setState({value: ''
  });
});

Saya tidak dapat melihat pro dan kontra dari dua alternatif tersebut, jika ada. Terima kasih.

gabrielgiussi
sumber
Apakah saya melewatkan sesuatu di sini? Mengapa Anda tidak menggunakan objek acara untuk mendapatkan nilai formulir? Tampaknya itulah satu-satunya alasan untuk menggunakan formulir di sini sejak awal. Jika Anda tidak menggunakan perilaku kirim default dan memiliki referensi pada masukan, Anda tidak perlu menggabungkannya dalam formulir.
NectarSoft

Jawaban:

143

Versi singkatnya: hindari referensi.


Mereka buruk untuk pemeliharaan, dan kehilangan banyak kesederhanaan yang disediakan model WYSIWYG.

Anda memiliki formulir. Anda perlu menambahkan tombol yang mengatur ulang formulir.

  • referensi:
    • memanipulasi DOM
    • render menjelaskan bagaimana formulir terlihat 3 menit yang lalu
  • negara
    • setState
    • render menjelaskan bagaimana bentuk terlihat

Anda memiliki kolom nomor CCV di input dan beberapa kolom lain di aplikasi Anda yang berupa angka. Sekarang Anda perlu memaksa pengguna hanya memasukkan angka.

  • referensi:
    • tambahkan handler onChange (bukankah kita menggunakan ref untuk menghindari ini?)
    • memanipulasi dom di onChange jika itu bukan angka
  • negara
    • Anda sudah memiliki penangan onChange
    • tambahkan pernyataan if, jika tidak valid jangan lakukan apa pun
    • render hanya dipanggil jika itu akan menghasilkan hasil yang berbeda

Eh, lupakan, PM ingin kita lakukan saja box-shadow merah kalau tidak valid.

  • referensi:
    • buat penangan onChange panggil saja forceUpdate atau apalah?
    • membuat hasil render berdasarkan ... ya?
    • di mana kita mendapatkan nilai untuk divalidasi dalam render?
    • memanipulasi properti dom className elemen secara manual?
    • saya tersesat
    • menulis ulang tanpa referensi?
    • baca dari dom dalam render jika kita dipasang jika tidak, anggap valid?
  • negara:
    • hapus pernyataan if
    • membuat render memvalidasi berdasarkan this.state

Kita perlu memberikan kendali kembali kepada orang tua. Data sekarang ada dalam alat peraga dan kami perlu bereaksi terhadap perubahan.

  • referensi:
    • implementasikan componentDidMount, componentWillUpdate, dan componentDidUpdate
    • secara manual membedakan alat peraga sebelumnya
    • memanipulasi dom dengan set perubahan minimal
    • Hei! kami menerapkan react in react ...
    • masih ada lagi, tapi jariku sakit
  • negara:
    • sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js

Orang-orang berpikir ref 'lebih mudah' daripada menyimpannya di negara bagian. Ini mungkin benar untuk 20 menit pertama, itu tidak benar menurut pengalaman saya setelah itu. Tempatkan diri Anda pada posisi untuk mengatakan "Ya, saya akan menyelesaikannya dalam 5 menit" daripada "Oke, saya akan menulis ulang beberapa komponen".

Perampok
sumber
3
Bisakah Anda menjelaskan lebih banyak tentang sed -e 's / this.state / this.props /' 's / handleChange / onChange /' -i form.js?
gabrielgiussi
1
Tidak, maksud saya perubahan nyata pada dom. React.findDOMNode(this.refs.foo). Jika Anda misalnya berubah, this.refs.foo.props.bartidak akan ada yang terjadi.
Brigand
1
misalnya jika Anda telah <input onChange={this.handleChange} value={this.state.foo} />mengubahnya menjadi <input onChange={this.props.handleChange} value={this.props.foo} />, atau memodifikasi fungsi handleChange Anda untuk memanggil callback dalam props. Bagaimanapun, itu adalah beberapa perubahan kecil yang jelas.
Brigand
4
Tidak yakin apakah saya satu-satunya yang menemukan jawaban Anda agak membingungkan. Bisakah Anda menunjukkan beberapa contoh kode yang membuat poin Anda lebih jelas?
Rishabh
2
Memiliki 50+ input di layar, rendering setiap perubahan status tidak diinginkan. inputMembuat komponen setiap bidang di mana masing-masing mempertahankan keadaannya sendiri adalah ideal. Pada titik tertentu kita memang perlu merekonsiliasi berbagai negara bagian independen ini dengan beberapa model yang lebih besar. Mungkin kita memiliki penyimpanan otomatis pada pengatur waktu, atau kita hanya menghemat componentWillUnmountDi sinilah menurut saya refsideal, selama rekonsiliasi kita memetik statenilai dari masing-masing ref, dan tidak ada yang lebih bijak. Saya setuju dalam banyak kasus stateadalah jawabannya, tetapi dengan sejumlah besar inputs, memanfaatkan refspola yang tepat adalah keuntungan kinerja
lux
105

Saya telah melihat beberapa orang mengutip jawaban di atas sebagai alasan untuk "jangan pernah menggunakan referensi" dan saya ingin memberikan pendapat saya (serta beberapa pengembang React lain yang pernah saya ajak bicara).

Sentimen "jangan gunakan referensi" benar ketika berbicara tentang menggunakannya untuk contoh komponen. Artinya, Anda tidak boleh menggunakan ref sebagai cara untuk mengambil instance komponen dan memanggil metode padanya. Ini adalah cara yang salah untuk menggunakan ref dan saat ref pergi ke selatan dengan cepat.

Cara yang benar (dan sangat berguna) untuk menggunakan ref adalah saat Anda menggunakannya untuk mendapatkan beberapa nilai dari DOM. Misalnya, jika Anda memiliki kolom input yang melampirkan ref ke input itu, maka mengambil nilainya nanti melalui ref sudah cukup. Tanpa cara ini, Anda perlu melalui proses yang cukup diatur untuk menjaga bidang input Anda tetap mutakhir dengan status lokal atau penyimpanan fluks Anda - yang tampaknya tidak perlu.

Edit 2019: Halo teman-teman di masa depan. Selain apa yang saya sebutkan beberapa tahun yang lalu ^, dengan React Hooks, ref juga merupakan cara yang bagus untuk melacak data antar render dan tidak terbatas hanya dengan mengambil node DOM.

Tyler McGinnis
sumber
3
Paragraf terakhir Anda sangat masuk akal, tetapi bisakah Anda memperjelas paragraf kedua? Apa contoh konkret mengambil instance komponen dan memanggil metode yang dianggap tidak benar?
Danny Libin
2
Saya setuju dengan ini. Saya menggunakan refs kecuali / sampai saya perlu melakukan validasi atau manipulasi nilai bidang. Jika saya perlu memvalidasi perubahan atau nilai secara terprogram, maka saya menggunakan status.
Christopher Davies
1
Saya setuju dengan ini juga. Selama fase penemuan, saya sengaja mendekati layar dengan sejumlah besar masukan dengan kenaifan. Semua nilai input disimpan dalam peta (dalam keadaan) yang dikunci oleh id. Tak perlu dikatakan, kinerja menurun sejak pengaturan status dan rendering 50+ input (beberapa material-ui, yang berat!) Pada perubahan UI kecil seperti klik kotak centang tidak ideal. Membuat komponen setiap masukan yang dapat mempertahankan statusnya sendiri tampaknya merupakan pendekatan yang tepat. Jika rekonsiliasi diperlukan, lihat saja refsdan dapatkan nilai negaranya. Sepertinya pola yang sangat bagus sebenarnya.
lux
2
Saya sangat setuju. Jawaban yang diterima terlalu kabur menurut saya.
James Wright
Saya setuju. Saat mendesain komponen Formulir umum, hal ini menjelaskan poin-poin penting dari komponen yang dikontrol dan mengelola fokus, penanganan kesalahan, dll. Sebenarnya, tidak mungkin untuk memiliki arsitektur yang bersih. Bicaralah dengan saya jika diperlukan. Saya memindahkan komponen saya ke ref.
kushalvm
6

TL; DR Secara umum,refs bertentangan dengan filosofi deklaratif React , jadi Anda harus menggunakannya sebagai pilihan terakhir. Gunakan state / propsbila memungkinkan.


Untuk memahami di mana Anda menggunakan refsvs state / props, mari kita lihat beberapa prinsip desain yang diikuti oleh React.

Per Bereaksi dokumentasi tentangrefs

Hindari menggunakan referensi untuk apa pun yang bisa dilakukan secara deklaratif.

Prinsip Desain Per React tentang Escape Hatches

Jika beberapa pola yang berguna untuk membangun aplikasi sulit diekspresikan dengan cara deklaratif, kami akan menyediakan API imperatif untuknya. (dan mereka menautkan ke referensi di sini)

Artinya tim React menyarankan untuk menghindar refs dan menggunakan state / propsapa pun yang dapat dilakukan dengan cara reaktif / deklaratif.

@Tyler McGinnis telah memberikan jawaban yang sangat bagus , juga menyatakan itu

Cara yang benar (dan sangat berguna) untuk menggunakan ref adalah ketika Anda menggunakannya untuk mendapatkan beberapa nilai dari DOM ...

Meskipun Anda bisa melakukan itu, Anda akan melawan filosofi React. Jika Anda memiliki nilai dalam suatu masukan, itu pasti berasal dari state / props. Untuk menjaga kode tetap konsisten dan dapat diprediksi, Anda juga harus tetap menggunakannya state / props. Saya mengakui fakta bahwa refsterkadang memberi Anda solusi yang lebih cepat, jadi jika Anda melakukan pembuktian konsep, cepat dan kotor dapat diterima.

Ini menyisakan beberapa kasus penggunaan konkret untukrefs

Mengelola fokus, pemilihan teks, atau pemutaran media. Memicu animasi imperatif. Mengintegrasikan dengan pustaka DOM pihak ketiga.

Lyubomir
sumber
5

Posting ini sudah lama.

Saya akan berbagi sedikit pengalaman saya tentang satu kasus tentang hal itu.

Saya sedang mengerjakan komponen besar (414 baris) dengan banyak input 'dinamis' dan banyak data cache yang terlibat. (Saya tidak bekerja sendirian di halaman, dan indra saya memberi tahu saya bahwa struktur kode mungkin dapat dipisahkan dengan lebih baik, tetapi bukan itu intinya (yah, bisa jadi tetapi saya sedang menghadapinya)

Saya pertama kali bekerja dengan negara untuk menangani nilai-nilai input:

  const [inputsValues, setInputsValues] = useState([])
  const setInputValue = (id, value) => {
    const arr = [...inputsValues]
    arr[id] = value
    setInputsValues(arr)
  }

dan tentu saja di masukan:

value={inputsValues[id] || ''}
onChange={event => setInputValue(id, event.target.value)}

Proses rendering sangat berat sehingga perubahan input terputus-putus seperti **** (jangan coba menekan tombol, teks hanya akan muncul setelah jeda)

Saya yakin saya bisa menghindari ini menggunakan referensi.

berakhir seperti ini:

  const inputsRef = useRef([])

dan di masukan:

ref={input => (inputsRef.current[id] = input)}

[baik dalam kasus saya, Input adalah Material-UI TextField jadi itu:

inputRef={input => (inputsRef.current[id] = input)}

]

Berkat ini, tidak ada perenderan, masukannya lancar, fungsinya bekerja dengan cara yang sama. Ini akan menghemat siklus dan perhitungan, begitu juga energi. Lakukan untuk bumi x)

Kesimpulan saya: useRef untuk nilai input bahkan bisa dibutuhkan.

Kaphar
sumber