React.js: Mengidentifikasi input yang berbeda dengan satu handler onChange

141

Penasaran apa cara yang tepat untuk mendekati ini adalah:

var Hello = React.createClass({
getInitialState: function() {
    return {total: 0, input1:0, input2:0};
},
render: function() {
    return (
        <div>{this.state.total}<br/>
            <input type="text" value={this.state.input1} onChange={this.handleChange} />
            <input type="text" value={this.state.input2} onChange={this.handleChange} />
        </div>
    );
},
handleChange: function(e){
    this.setState({ ??? : e.target.value});
    t = this.state.input1 + this.state.input2;
    this.setState({total: t});
}
});

React.renderComponent(<Hello />, document.getElementById('content'));

Jelas Anda bisa membuat fungsi handleChange yang terpisah untuk menangani setiap input yang berbeda, tapi itu tidak terlalu bagus. Demikian pula Anda dapat membuat komponen hanya untuk input individu, tetapi saya ingin melihat apakah ada cara untuk melakukannya seperti ini.

T3db0t
sumber

Jawaban:

162

Saya sarankan tetap menggunakan atribut HTML standar seperti namepada inputElemen untuk mengidentifikasi input Anda. Selain itu, Anda tidak perlu menjaga "total" sebagai nilai terpisah di negara karena itu dapat dikompilasi dengan menambahkan nilai lain di negara Anda:

var Hello = React.createClass({
    getInitialState: function() {
        return {input1: 0, input2: 0};
    },
    render: function() {
        const total = this.state.input1 + this.state.input2;

        return (
            <div>{total}<br/>
                <input type="text" value={this.state.input1} name="input1" onChange={this.handleChange} />
                <input type="text" value={this.state.input2} name="input2" onChange={this.handleChange} />
            </div>
        );
    },
    handleChange: function(e) {
        this.setState({[e.target.name]: e.target.value});
    }
});

React.renderComponent(<Hello />, document.getElementById('content'));
Ross Allen
sumber
3
Saya mencoba melakukan ini pada awalnya, tetapi setState ({e.target.name ... tidak berfungsi — ini adalah kesalahan sintaksis. Anda harus membuat objek temp dengan obj [e.target.name] dan setState untuk itu. Semacam ini bekerja, tetapi tampaknya ada semacam keterlambatan dalam memperbarui objek negara.
T3db0t
1
"Jenis penundaan" adalah pemutakhiran setState selama requestAnimationFrame (saya berasumsi), jadi abaikan komentar itu
T3db0t
24
@ T3db0t Sintaks ES6 ini berfungsi:this.setState({ [e.target.name]: e.target.value });
XåpplI'-I0llwlg'I -
2
Menggunakan bind adalah pendekatan yang lebih baik. Pendekatan ini tidak berfungsi jika Anda melampirkan pengendali onChange ke elemen tanpa properti nama, seperti div.
ericgrosse
3
@ ericgrosse bind tidak lebih baik dalam hal ini karena Anda membuat banyak fungsi yang tidak perlu. juga, Anda dapat menggunakan atribut data atau sesuatu pada elemen yang berbeda jika perlu
aw04
106

Anda dapat menggunakan .bindmetode ini untuk membuat parameter terlebih dahulu ke handleChangemetode. Itu akan menjadi sesuatu seperti:

  var Hello = React.createClass({
    getInitialState: function() {
        return {input1:0, 
                input2:0};
    },
    render: function() {
      var total = this.state.input1 + this.state.input2;
      return (
        <div>{total}<br/>
          <input type="text" value={this.state.input1} 
                             onChange={this.handleChange.bind(this, 'input1')} />
          <input type="text" value={this.state.input2} 
                             onChange={this.handleChange.bind(this, 'input2')} />
        </div>
      );
    },
    handleChange: function (name, e) {
      var change = {};
      change[name] = e.target.value;
      this.setState(change);
    }
  });

  React.renderComponent(<Hello />, document.getElementById('content'));

(Saya juga dibuat totaldihitung pada waktu render, karena itu adalah hal yang disarankan untuk dilakukan.)

fiatjaf
sumber
13
Hanya pengingat cepat yang this.handleChange.bind(...)menciptakan fungsi baru. Dalam kasus Anda menggunakan shouldComponentUpdatedengan PureRenderMixinatau yang serupa itu akan pecah. Semua komponen input Anda akan dirender ulang ketika nilai tunggal berubah.
zemirco
5
Jika Anda mengubah implementasi handleChangeuntuk handleChange(name) { return event => this.setState({name: event.target.value}); }Anda dapat melewati fungsi "sama" (tidak akan membuat fungsi baru seperti yang dilakukan dengan menggunakan .bind()Kemudian, Anda dapat melewati fungsi tersebut:this.handleChange("input1")
Andreyco
1
Saya pikir juga penting untuk menyebutkan, bahwa sifat setState, adalah bahwa seseorang tidak akan dapat mengambil status saat ini di fungsi handChange, tetapi keadaan sebelumnya menggunakan, this.state.input1, misalnya. Pendekatan yang tepat adalah membuat callback seperti this.setState(change, function () { console.log(this.state.input1); );referensi: stackoverflow.com/questions/30782948/…
Charlie-Greenman
39

The onChangeevent gelembung ... Jadi Anda bisa melakukan sesuatu seperti ini:

// A sample form
render () {
  <form onChange={setField}>
    <input name="input1" />
    <input name="input2" />
  </form>
}

Dan metode setField Anda mungkin terlihat seperti ini (dengan asumsi Anda menggunakan ES2015 atau lebih baru:

setField (e) {
  this.setState({[e.target.name]: e.target.value})
}

Saya menggunakan sesuatu yang mirip dengan ini di beberapa aplikasi, dan itu sangat berguna.

Christopher Davies
sumber
11

Solusi usang

valueLink/checkedLinktidak digunakan lagi dari core Bereaksi, karena membingungkan sebagian pengguna. Jawaban ini tidak akan berfungsi jika Anda menggunakan React versi terbaru. Tetapi jika Anda suka, Anda dapat dengan mudah meniru dengan membuat Inputkomponen Anda sendiri

Konten jawaban lama:

Apa yang ingin Anda capai bisa jauh lebih mudah dicapai dengan menggunakan 2-way data binding help of React.

var Hello = React.createClass({
    mixins: [React.addons.LinkedStateMixin],
    getInitialState: function() {
        return {input1: 0, input2: 0};
    },

    render: function() {
        var total = this.state.input1 + this.state.input2;
        return (
            <div>{total}<br/>
                <input type="text" valueLink={this.linkState('input1')} />;
                <input type="text" valueLink={this.linkState('input2')} />;
            </div>
        );
    }

});

React.renderComponent(<Hello />, document.getElementById('content'));

Mudah bukan?

http://facebook.github.io/react/docs/two-way-binding-helpers.html

Anda bahkan dapat menerapkan mixin Anda sendiri

Sebastien Lorber
sumber
Mengapa kita harus mengikat pertukaran untuk mengatur negara. Lagipula itu adalah ReactJS!
Junaid Qadir
Perhatikan bahwa solusi ini sudah usang
Philipp
6

Anda juga dapat melakukannya seperti ini:

...
constructor() {
    super();
    this.state = { input1: 0, input2: 0 };
    this.handleChange = this.handleChange.bind(this);
}

handleChange(input, value) {
    this.setState({
        [input]: value
    })
}

render() {
    const total = this.state.input1 + this.state.input2;
    return (
        <div>
            {total}<br />
            <input type="text" onChange={e => this.handleChange('input1', e.target.value)} />
            <input type="text" onChange={e => this.handleChange('input2', e.target.value)} />
        </div>
    )
}
inostia
sumber
tidak bekerja untuk saya. lihat Bereaksi alat pengembang. itu menciptakan dan menetapkan nilai ke variabel / objek yang disebut input, bukan input1 / input2
Gaurravs
1
@ Gaurravs ya Anda benar. Saya perlu menambahkan []sekitar inputke setState. Itu membuat properti
dinamai
4

Anda dapat menggunakan khusus Reactatribut yang disebut refdan kemudian mencocokkan node DOM nyata dalam onChangeacara menggunakan React's getDOMNode()fungsi:

handleClick: function(event) {
  if (event.target === this.refs.prev.getDOMNode()) {
    ...
  }
}

render: function() {
  ...
  <button ref="prev" onClick={this.handleClick}>Previous question</button>
  <button ref="next" onClick={this.handleClick}>Next question</button>
  ...
}
Janusz Kacalak
sumber
Setidaknya dalam 0,13 this.refs tidak memiliki pref properti.
blub
2
@usagidon - prevhanya nama yang saya atur dalam render()metode ini
Janusz Kacalak
2
Pada React v0.14, Anda bisa melakukannya event.target === this.refs.prev. facebook.github.io/react/blog/2015/10/10/…
XåpplI'-I0llwlg'I -
0

@Vigril Disgr4ce

Ketika datang ke bentuk multi-bidang, masuk akal untuk menggunakan fitur utama React: komponen.

Dalam proyek saya, saya membuat komponen TextField, yang mengambil prop nilai minimal, dan menangani penanganan perilaku umum bidang input teks. Dengan cara ini Anda tidak perlu khawatir tentang melacak nama bidang saat memperbarui status nilai.

[...]

handleChange: function(event) {
  this.setState({value: event.target.value});
},
render: function() {
  var value = this.state.value;
  return <input type="text" value={value} onChange={this.handleChange} />;
}

[...]
manu3569
sumber
0

Anda dapat melacak nilai setiap anak inputdengan membuat InputFieldkomponen terpisah yang mengelola nilai satu anak input. Misalnya InputFieldbisa:

var InputField = React.createClass({
  getInitialState: function () {
    return({text: this.props.text})
  },
  onChangeHandler: function (event) {
     this.setState({text: event.target.value})
  }, 
  render: function () {
    return (<input onChange={this.onChangeHandler} value={this.state.text} />)
  }
})

Sekarang nilai masing-masing inputdapat dilacak dalam instance terpisah dari InputFieldkomponen ini tanpa membuat nilai terpisah dalam status induk untuk memantau setiap komponen anak.

Javasamurai
sumber
0

Saya akan memberikan solusi yang sangat sederhana untuk masalah ini. Misalkan kita memiliki dua input usernamedan password, tetapi kita ingin pegangan kita menjadi mudah dan generik, sehingga kita dapat menggunakannya kembali dan tidak menulis kode boilerplate.

I. bentuk Kami:

                <form>
                    <input type="text" name = "username" onChange={this.onChange} value={this.state.username}/>
                    <input type="text" name = "password" onChange={this.onChange} value={this.state.password}/>
                    <br></br>
                    <button type="submit">Submit</button>
                </form>

II. Konstruktor kami, yang ingin kami simpan usernamedan password, sehingga kami dapat mengaksesnya dengan mudah:

constructor(props) {
    super(props);
    this.state = {
        username: '',
        password: ''
    };

    this.onSubmit = this.onSubmit.bind(this);
    this.onChange = this.onChange.bind(this);
}

III. Pegangan yang menarik dan "generik" dengan hanya satu onChangeacara didasarkan pada ini:

onChange(event) {
    let inputName = event.target.name;
    let value = event.target.value;

    this.setState({[inputName]:value});


    event.preventDefault();
}

Biarkan saya jelaskan:

1.When perubahan terdeteksi onChange(event)itu disebut

2.Kemudian kita mendapatkan parameter nama field dan nilainya:

let inputName = event.target.name; ex: username

let value = event.target.value; ex: itsgosho

3. Berdasarkan parameter nama, kami mendapatkan nilai kami dari status di konstruktor dan memperbaruinya dengan nilai:

this.state['username'] = 'itsgosho'

4. Kunci yang perlu diperhatikan di sini adalah bahwa nama bidang harus cocok dengan parameter kami di negara bagian

Semoga saya membantu seseorang entah bagaimana :)

Georgi Peev
sumber
0

Kunci negara Anda harus sama dengan nama bidang input Anda. Kemudian Anda dapat melakukan ini dalam metode handleEvent;

this.setState({
        [event.target.name]: event.target.value
});
Rajan
sumber
-1

Hai, sudah memperbaiki jawaban sallallen . Anda tidak perlu mengikat fungsi karena Anda dapat mengakses input tanpa itu.

var Hello = React.createClass({
    render: function() {
        var total = this.state.input1 + this.state.input2;
        return (
             <div>{total}<br/>
                  <input type="text" 
                    value={this.state.input1}
                    id="input1"  
                    onChange={this.handleChange} />
                 <input type="text" 
                    value={this.state.input2}
                    id="input2" 
                    onChange={this.handleChange} />
            </div>
       );
   },
   handleChange: function (name, value) {
       var change = {};
       change[name] = value;
       this.setState(change);
   }
});

React.renderComponent(<Hello />, document.getElementById('content'));
Albert Olivé
sumber