Menginisialisasi bidang terkontrol setelah konstruksi

Saya mencoba menginisialisasi bidang terkontrol sebagai reaksi, tetapi saya tidak tahu nilai awalnya selama konstruksi.

Pemahaman saya adalah meskipun Anda melakukan setState, yang menyebabkan rendering ulang, ini tidak akan mengubah nilai kontrol - namun saya tidak yakin mengapa.

Jadi, yang berikut ini tidak akan berfungsi:

componentDidMount() {

   ...   // code to get value

   this.setState({ value: "hello world" });
   return ( <input type="text" value={this.state.value} onChange={this.handleChange} />
}

Sebagai gantinya, saya mencoba merender input dalam panggilan balik setState - untuk memastikan bahwa nilainya telah ditetapkan:

componentDidMount() {

   ...   // code to get value

   this.setState({ value: "hello world" }, this.renderInput);
}

renderInput = () => {
   this.input = ( <input type="text" value={this.state.value} onChange={this.handleChange} />
}

Catatan: formulir saya menyertakan {ini.input)

Pada contoh kedua, formulir saya ditampilkan dengan sempurna, dan masukan diinisialisasi. Namun, kemudian fungsi onChange dipanggil, meskipun memperbarui status dengan benar, perubahan status tidak diambil - kolom input saya dibekukan, seolah-olah tidak ada onChange sama sekali.

Ini benar-benar membuat saya bingung dan saya ingin tahu apakah ada cara untuk menginisialisasi bidang saya tanpa harus memanggil fungsi yang berpotensi lambat di dalam konstruksi.


person Ben    schedule 12.04.2018    source sumber
comment
Mengapa Anda mengembalikan <input> dari componentDidMount()? Apa yang this.handleChangemu lakukan? dapatkah Anda memasukkan fungsi render() Anda?   -  person Pipe    schedule 12.04.2018
comment
Setuju, menurut saya mengembalikan elemen dari componentDidMount tidak akan menghasilkan apa-apa.   -  person ecraig12345    schedule 13.04.2018
comment
Kita juga pasti perlu melihat handleChange, karena mungkin di situlah masalahnya   -  person ecraig12345    schedule 13.04.2018


Jawaban (1)


EDIT: Saat membaca ulang, saya menyadari kode Anda secara efektif melakukan hal yang sama dengan yang disarankan oleh jawaban asli saya (tetapi dengan cara yang sangat non-idiomatis). Mungkin masalah sebenarnya ada di handleChange Anda, tetapi saya akan meninggalkan jawaban asli karena ini menunjukkan cara menunggu yang lebih idiomatis untuk merender bidang tersebut.


(jawaban asli)

Solusi paling sederhana adalah dengan tidak merender <input> sampai Anda mengetahui nilai awalnya. Gunakan sesuatu seperti ini di tempat yang tepat di render():

{ typeof this.state.value === 'string' ?
  <input type="text" value={this.state.value} onChange={this.handleChange} /> :
  null }

Kelemahan dari pendekatan ini: jika ada elemen lain dalam formulir, elemen tersebut akan "melompat" saat bidang ini muncul, dan ini tidak bagus.

Untuk menghindari lompatan, Anda dapat menunggu untuk merender semua kontrol formulir hingga semua nilai awal tersedia. Tambahkan properti this.state.isLoading yang awalnya benar, lalu setel ke salah saat pemuatan selesai. (Demi kenyamanan, contoh kode mengasumsikan Anda memiliki fungsi getInitialValue() yang mengembalikan janji, tetapi Anda dapat melakukan hal serupa dengan callback atau konstruksi lainnya.)

componentDidMount() {
  getInitialValue().then((initialValue) => {
    this.setState({ value: initialValue, isLoading: false });
  });
}

render() {
  if (this.state.isLoading)
    return null; // or something like <div>Loading...</div>

  // else, return normal stuff
}
person ecraig12345    schedule 13.04.2018