React, ES6 - getInitialState didefinisikan pada kelas JavaScript biasa

115

Saya memiliki komponen berikut ( radioOther.jsx):

 'use strict';

 //module.exports = <-- omitted in update

   class RadioOther extends React.Component {

     // omitted in update 
     // getInitialState() {
     //    propTypes: {
     //        name: React.PropTypes.string.isRequired
     //    }
     //    return {
     //       otherChecked: false
     //   }
     // }

     componentDidUpdate(prevProps, prevState) {
         var otherRadBtn = this.refs.otherRadBtn.getDOMNode();

         if (prevState.otherChecked !== otherRadBtn.checked) {
             console.log('Other radio btn clicked.')
             this.setState({
                 otherChecked: otherRadBtn.checked,
             });
         }
     }

     onRadChange(e) {
         var input = e.target;
         this.setState({
             otherChecked: input.checked
         });
     }

     render() {
         return (
             <div>
                 <p className="form-group radio">
                     <label>
                         <input type="radio"
                                ref="otherRadBtn"
                                onChange={this.onRadChange}
                                name={this.props.name}
                                value="other"/>
                         Other
                     </label>
                     {this.state.otherChecked ?
                         (<label className="form-inline">
                             Please Specify:
                             <input
                                 placeholder="Please Specify"
                                 type="text"
                                 name="referrer_other"
                                 />
                         </label>)
                         :
                         ('')
                     }
                 </p>
             </div>
         )
     }
 };

Sebelum menggunakan ECMAScript6 semuanya baik-baik saja, sekarang saya mendapatkan 1 kesalahan, 1 peringatan dan saya memiliki pertanyaan tindak lanjut:

Kesalahan: TypeError Tidak Tertangkap: Tidak dapat membaca properti 'otherChecked' dari null

Peringatan: getInitialState didefinisikan di RadioOther, kelas JavaScript biasa. Ini hanya didukung untuk kelas yang dibuat menggunakan React.createClass. Apakah Anda bermaksud mendefinisikan properti negara?


  1. Adakah yang bisa melihat di mana letak kesalahan, saya tahu itu karena pernyataan bersyarat di DOM tetapi ternyata saya tidak menyatakan nilai awalnya dengan benar?

  2. Haruskah saya membuat getInitialState menjadi statis

  3. Di mana tempat yang tepat untuk mendeklarasikan proptypes saya jika getInitialState salah?

MEMPERBARUI:

   RadioOther.propTypes = {
       name: React.PropTypes.string,
       other: React.PropTypes.bool,
       options: React.PropTypes.array }

   module.exports = RadioOther;

@ssorallen, kode ini:

     constructor(props) {
         this.state = {
             otherChecked: false,
         };
     }

menghasilkan "Uncaught ReferenceError: this is not defined", dan sementara di bawah mengoreksinya

     constructor(props) {
     super(props);
         this.state = {
             otherChecked: false,
         };
     }

tetapi sekarang, mengklik tombol lain sekarang menghasilkan kesalahan:

Uncaught TypeError: Cannot read property 'props' of undefined

Talha Awan
sumber
1
Perubahan lain untuk kelas ES6 adalah bahwa metode tidak "terikat otomatis" ke instance, artinya saat Anda meneruskan fungsi seperti onChange={this.onRadChange}, thistidak merujuk ke instance saat onRadChangedipanggil. Anda perlu callback mengikat dalam renderatau melakukannya di constructor: onChange={this.onRadChange.bind(this)}.
Ross Allen

Jawaban:

239
  • getInitialStatetidak digunakan di kelas ES6. Sebagai gantinya tetapkan this.statedi konstruktor.
  • propTypes harus variabel kelas statis atau ditugaskan ke kelas, itu tidak boleh ditugaskan ke contoh komponen.
  • Metode anggota tidak "terikat otomatis" di kelas ES6. Untuk metode yang digunakan sebagai callback, gunakan penginisialisasi properti kelas atau tetapkan instance terikat di konstruktor.
export default class RadioOther extends React.Component {

  static propTypes = {
    name: React.PropTypes.string.isRequired,
  };

  constructor(props) {
    super(props);
    this.state = {
      otherChecked: false,
    };
  }

  // Class property initializer. `this` will be the instance when
  // the function is called.
  onRadChange = () => {
    ...
  };

  ...

}

Lihat lebih lanjut dalam dokumentasi React tentang ES6 Classes: Mengubah Fungsi menjadi Class

Ross Allen
sumber
Setahun berlalu dan sekarang Anda mungkin menemukan Anda mendapatkan: Uncaught TypeError: Cannot read property 'bind' of undefinederror Ada ide?
Jamie Hutber
@JamieHutber Bisakah Anda membuat pertanyaan baru dengan kode Anda? Jika metode ini didefinisikan di kelas, saya tidak tahu mengapa Anda mendapatkan kesalahan itu.
Ross Allen
Terima kasih atas sarannya, @KennWorden. Saya membuka masalah untuk dokumen React: github.com/facebook/react/issues/7746
Ross Allen
Apakah 'mengikat mereka di tempat' berarti menggunakan fungsi panah seperti yang Anda tunjukkan di atas? Itu berhasil, tentu saja. Oh, javascript!
jomofrodo
@jomofrodo Itu ambigu, terima kasih telah menunjukkannya. Maksud saya, renderAnda dapat melakukan sesuatu seperti onClick={this.doFoo.bind(this)}, tetapi saya sengaja tidak memasukkannya ke dalam kode karena itulah cara yang paling tidak efisien untuk mengikat karena renderdapat sering dipanggil dan akan membuat fungsi baru pada setiap panggilan. Saya akan menghapus bahasa itu dari jawabannya.
Ross Allen
4

Menambah jawaban Ross .

Anda juga bisa menggunakan fungsi panah ES6 baru di properti onChange

Ini secara fungsional setara dengan mendefinisikan this.onRadChange = this.onRadChange.bind(this);di konstruktor tetapi lebih ringkas menurut saya.

Dalam kasus Anda, tombol radio akan terlihat seperti di bawah ini.

<input type="radio"
       ref="otherRadBtn"
       onChange={(e)=> this.onRadChange(e)}
       name={this.props.name}
       value="other"/>

Memperbarui

Metode "lebih ringkas" ini kurang efisien daripada opsi yang disebutkan dalam jawaban @Ross Allen karena menghasilkan fungsi baru setiap kali render()metode tersebut dipanggil

Sudarshan
sumber
1
Solusi ini benar secara fungsional, tetapi menghasilkan Fungsi baru pada setiap panggilan ke render(yang dapat dipanggil berkali-kali). Dengan menggunakan penginisialisasi properti kelas atau pengikatan dalam konstruktor, hanya satu Fungsi terikat baru yang dibuat pada konstruksi komponen dan tidak ada Fungsi baru yang dibuat selama render.
Ross Allen
1

Jika Anda menggunakan babel-plugin-transform-class-properties atau babel-preset-stage-2 (atau stage-1, atau stage-0), Anda dapat menggunakan sintaks ini:

class RadioOther extends React.Component {

  static propTypes = {
    name: React.PropTypes.string,
    ...
  };

  state = {
      otherChecked: false,
  };

  onRadChange = () => {
    ...
  };

  ...

}
danau
sumber