React.js: Xác định các đầu vào khác nhau bằng một trình xử lý onChange


141

Tò mò cách đúng đắn để tiếp cận điều này là:

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'));

Rõ ràng bạn có thể tạo các hàm xử lý riêng biệt để xử lý từng đầu vào khác nhau, nhưng điều đó không hay lắm. Tương tự như vậy, bạn có thể tạo một thành phần chỉ cho một đầu vào riêng lẻ, nhưng tôi muốn xem liệu có cách nào để làm điều đó như thế này không.

Câu trả lời:


162

Tôi khuyên bạn nên bám vào các thuộc tính HTML tiêu chuẩn như nametrên inputElement để xác định đầu vào của bạn. Ngoài ra, bạn không cần giữ "tổng" là một giá trị riêng biệt ở trạng thái vì nó có thể kết hợp bằng cách thêm các giá trị khác trong trạng thái của bạn:

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'));

3
Tôi đã cố gắng thực hiện điều này ban đầu, nhưng setState ({e.target.name ... không hoạt động, đó là lỗi cú pháp. Bạn phải tạo một đối tượng tạm thời với obj [e.target.name] và setState để điều đó. Đây là loại công việc, nhưng dường như có một số độ trễ trong việc cập nhật đối tượng trạng thái.
T3db0t

1
"Loại độ trễ" là setState cập nhật trong requestAnimationFrame (tôi giả sử), vì vậy hãy bỏ qua nhận xét đó
T3db0t

24
@ T3db0t Cú pháp ES6 này hoạt động:this.setState({ [e.target.name]: e.target.value });
XåpplI'-I0llwlg'I -

2
Sử dụng ràng buộc là cách tiếp cận tốt hơn. Cách tiếp cận này không hoạt động nếu bạn đính kèm trình xử lý onChange vào một phần tử không có thuộc tính tên, chẳng hạn như div.
ericgrosse

3
@ericgrosse liên kết không tốt hơn trong trường hợp này vì bạn đang tạo ra rất nhiều chức năng không cần thiết. ngoài ra, bạn có thể sử dụng thuộc tính data- hoặc thứ gì đó trên một loại phần tử khác nếu cần
aw04

106

Bạn có thể sử dụng .bindphương thức để xây dựng trước các tham số cho handleChangephương thức. Nó sẽ giống như:

  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'));

(Tôi cũng đã thực hiện totaltính toán tại thời điểm kết xuất, vì đó là điều nên làm.)


13
Chỉ cần một lời nhắc nhở nhanh chóng this.handleChange.bind(...)tạo ra một chức năng mới. Trong trường hợp bạn đang sử dụng shouldComponentUpdatevới PureRenderMixinhoặc một cái gì đó tương tự, nó sẽ bị hỏng. Tất cả các thành phần đầu vào của bạn sẽ được đăng ký lại khi một giá trị duy nhất thay đổi.
zemirco

5
Nếu bạn thay đổi triển khai handleChangethành handleChange(name) { return event => this.setState({name: event.target.value}); }bạn có thể chuyển chức năng "tương tự" (sẽ không tạo chức năng mới như đã thực hiện bằng cách sử dụng .bind()Then, bạn có thể chuyển chức năng đó:this.handleChange("input1")
Andreyco 10/2/2016

1
Tôi nghĩ điều quan trọng cần đề cập là, bản chất của setState, là người ta sẽ không thể truy xuất trạng thái hiện tại trong hàm handChange, nhưng trạng thái trước đó sử dụng, this.state.input1, chẳng hạn. Một cách tiếp cận phù hợp sẽ là tạo ra một cuộc gọi lại, chẳng hạn như this.setState(change, function () { console.log(this.state.input1); );tham chiếu: stackoverflow.com/questions/30782948/ mẹo
Charlie-Greenman

38

Các onChangesự kiện bong bóng ... Vì vậy, bạn có thể làm một cái gì đó như thế này:

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

Và phương thức setField của bạn có thể trông như thế này (giả sử bạn đang sử dụng ES2015 trở lên:

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

Tôi sử dụng một cái gì đó tương tự như thế này trong một số ứng dụng và nó khá tiện dụng.


11

Giải pháp không dùng nữa

valueLink/checkedLinkkhông được dùng từ React cốt lõi, vì nó gây nhầm lẫn cho một số người dùng. Câu trả lời này sẽ không hoạt động nếu bạn sử dụng phiên bản React gần đây. Nhưng nếu bạn thích nó, bạn có thể dễ dàng mô phỏng nó bằng cách tạo Inputthành phần của riêng bạn

Nội dung câu trả lời cũ:

Những gì bạn muốn đạt được có thể dễ dàng đạt được hơn nhiều bằng cách sử dụng các trình trợ giúp liên kết dữ liệu 2 chiều của 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'));

Dễ dàng phải không?

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

Bạn thậm chí có thể thực hiện mixin của riêng bạn


Tại sao chúng ta phải ràng buộc một onchange để thiết lập trạng thái. Đó là ReactJS sau tất cả!
Qadir

Lưu ý rằng giải pháp này không được chấp nhận
Philipp

6

Bạn cũng có thể làm như thế này:

...
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>
    )
}

đã không làm việc cho tôi. thấy công cụ phát triển React. nó tạo và gán các giá trị cho biến / đối tượng được gọi là đầu vào, thay vì input1 / input2
Gaurravs

1
@Gaurravs đúng rồi. Tôi cần thêm []xung quanh inputvào setState. Điều đó làm cho tính năng động của tài sản được giao
inostia

4

Bạn có thể sử dụng một đặc biệt Reactthuộc tính gọi refvà sau đó kết hợp các nút DOM thực sự trong onChangesự kiện sử dụng Reactcủa getDOMNode()chức năng:

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>
  ...
}

Ít nhất trong 0.13 this.refs không có tài sản pref.
blub

2
@usagidon - prevchỉ là một cái tên mà tôi đặt trong render()phương thức
Janusz Kacalak

2
Kể từ React v0.14, bạn có thể làm event.target === this.refs.prev. facebook.github.io/react/blog/2015/10/07/
Ấn

0

@Vigril Disgr4ce

Khi nói đến các hình thức đa trường, sẽ rất hợp lý khi sử dụng tính năng chính của React: các thành phần.

Trong các dự án của mình, tôi tạo các thành phần TextField, tối thiểu hóa giá trị prop và nó xử lý các hành vi phổ biến của trường văn bản đầu vào. Bằng cách này, bạn không phải lo lắng về việc theo dõi tên trường khi cập nhật trạng thái giá trị.

[...]

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} />;
}

[...]

0

Bạn có thể theo dõi giá trị của từng đứa trẻ inputbằng cách tạo một InputFieldthành phần riêng quản lý giá trị của một đứa trẻ input. Ví dụ: InputFieldcó thể là:

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} />)
  }
})

Bây giờ giá trị của mỗi inputcó thể được theo dõi trong một thể hiện riêng biệt của InputFieldthành phần này mà không tạo các giá trị riêng biệt trong trạng thái của cha mẹ để giám sát từng thành phần con.


0

Tôi sẽ cung cấp giải pháp thực sự đơn giản cho vấn đề. Giả sử chúng ta có hai đầu vào usernamepassword, nhưng chúng ta muốn xử lý của chúng ta dễ dàng và chung chung, vì vậy chúng ta có thể sử dụng lại và không viết mã soạn sẵn.

Hình thức của chúng tôi:

                <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. Nhà xây dựng của chúng tôi, mà chúng tôi muốn lưu usernamepasswordvì vậy chúng tôi có thể truy cập chúng dễ dàng:

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

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

III. Xử lý thú vị và "chung chung" chỉ với một onChangesự kiện dựa trên điều này:

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

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


    event.preventDefault();
}

Hãy để tôi giải thích:

1. Khi một sự thay đổi được phát hiện onChange(event)được gọi là

2.Sau đó, chúng tôi nhận được tham số tên của trường và giá trị của nó:

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

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

3. Dựa trên tham số tên, chúng tôi nhận được giá trị của chúng tôi từ trạng thái trong hàm tạo và cập nhật nó với giá trị:

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

4. Chìa khóa cần lưu ý ở đây là tên của trường phải khớp với tham số của chúng ta trong trạng thái

Hy vọng tôi đã giúp được ai đó :)


0

Khóa của trạng thái của bạn phải giống như tên của trường đầu vào của bạn. Sau đó, bạn có thể làm điều này trong phương thức handleEvent;

this.setState({
        [event.target.name]: event.target.value
});

-1

Hi có cải thiện ssorallen câu trả lời. Bạn không cần phải liên kết chức năng bởi vì bạn có thể truy cập vào đầu vào mà không có nó.

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'));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.