React.js: การระบุอินพุตที่แตกต่างด้วย one onChange handler


142

อยากรู้ว่าทางที่ถูกต้องในการเข้าหาคือ:

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

เห็นได้ชัดว่าคุณสามารถสร้างฟังก์ชั่นการจัดการที่แยกจากกันเพื่อจัดการอินพุตที่แตกต่างกัน แต่มันไม่ได้ดีมาก ในทำนองเดียวกันคุณสามารถสร้างองค์ประกอบสำหรับอินพุตเดี่ยว แต่ฉันต้องการดูว่ามีวิธีทำเช่นนี้หรือไม่

คำตอบ:


163

ฉันขอแนะนำให้ใช้คุณลักษณะ HTML มาตรฐานเช่นเดียวnameกับinputองค์ประกอบเพื่อระบุอินพุตของคุณ นอกจากนี้คุณไม่จำเป็นต้องให้ "รวม" เป็นค่าแยกต่างหากในสถานะเนื่องจากสามารถเรียบเรียงได้โดยการเพิ่มค่าอื่น ๆ ในสถานะของคุณ:

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
ฉันพยายามทำสิ่งนี้ในตอนแรก แต่ setState ({e.target.name ... ไม่ทำงาน - เป็นข้อผิดพลาดทางไวยากรณ์คุณต้องสร้างวัตถุ temp ด้วย obj [e.target.name] และ setState งานประเภทนี้ แต่ดูเหมือนว่าจะมีความล่าช้าในการอัปเดตออบเจ็กต์ของรัฐบางประเภท
T3db0t

1
"ชนิดของความล่าช้า" ถูกตั้งค่าให้อัพเดตสถานะในระหว่าง requestAnimationFrame (ฉันถือว่า) ดังนั้นให้ละเว้นคำพูดนั้น
T3db0t

24
@ T3db0t ไวยากรณ์ ES6 นี้ใช้งานได้:this.setState({ [e.target.name]: e.target.value });
XåpplI'-I0llwlg'I -

2
การใช้การผูกเป็นวิธีที่ดีกว่า วิธีการนี้ใช้ไม่ได้หากคุณแนบตัวจัดการ onChange กับองค์ประกอบที่ไม่มีคุณสมบัติชื่อเช่น div
ericgrosse

3
@ericgrosse การผูกไม่ดีขึ้นในกรณีนี้เพราะคุณกำลังสร้างฟังก์ชั่นที่ไม่จำเป็นมากมาย นอกจากนี้คุณยังสามารถใช้ data- attribute หรือบางอย่างในองค์ประกอบที่แตกต่างกันถ้าจำเป็นต้องเป็น
aw04

106

คุณสามารถใช้.bindวิธีการสร้างพารามิเตอร์ล่วงหน้ากับhandleChangeวิธี มันจะเป็นสิ่งที่ชอบ:

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

(ฉันtotalถูกคำนวณด้วยเวลาเรนเดอร์เนื่องจากเป็นสิ่งที่แนะนำให้ทำ)


13
เพียงเตือนความจำอย่างรวดเร็วที่this.handleChange.bind(...)สร้างฟังก์ชั่นใหม่ ในกรณีที่คุณใช้shouldComponentUpdateกับPureRenderMixinหรือสิ่งที่คล้ายกันมันจะแตก ส่วนประกอบอินพุตทั้งหมดของคุณจะถูกจัดแสดงใหม่เมื่อมีการเปลี่ยนแปลงค่าเดียว
zemirco

5
หากคุณเปลี่ยนการใช้งานhandleChangeไปเป็นhandleChange(name) { return event => this.setState({name: event.target.value}); }คุณสามารถส่งผ่านฟังก์ชัน "เดียวกัน" (จะไม่สร้างฟังก์ชันใหม่ตามที่ทำโดยใช้.bind()จากนั้นคุณสามารถส่งผ่านฟังก์ชั่นดังกล่าว:this.handleChange("input1")
Andreyco

1
ฉันคิดว่ามันเป็นสิ่งสำคัญที่จะพูดถึงเช่นกันว่าธรรมชาติของ setState นั้นเป็นสิ่งที่ไม่สามารถเรียกคืนสถานะปัจจุบันในฟังก์ชั่น handChange แต่ก่อนหน้านี้ใช้รัฐนี้ วิธีการที่เหมาะสมคือการสร้างการติดต่อกลับเช่นthis.setState(change, function () { console.log(this.state.input1); );การอ้างอิง: stackoverflow.com/questions/30782948/…
Charlie-Greenman

39

onChangeเหตุการณ์ฟอง ... ดังนั้นคุณสามารถทำอะไรเช่นนี้

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

และวิธี setField ของคุณอาจมีลักษณะเช่นนี้ (สมมติว่าคุณใช้ ES2015 หรือใหม่กว่า:

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

ฉันใช้สิ่งที่คล้ายกับสิ่งนี้ในหลาย ๆ แอพและมันค่อนข้างมีประโยชน์


11

โซลูชันที่เลิกใช้แล้ว

valueLink/checkedLinkถูกคัดค้านจากการทำปฏิกิริยาหลักเพราะมันทำให้ผู้ใช้บางคนสับสน คำตอบนี้จะไม่ทำงานหากคุณใช้ React รุ่นล่าสุด แต่ถ้าคุณชอบคุณสามารถเลียนแบบได้โดยการสร้างInputองค์ประกอบของคุณเอง

เนื้อหาคำตอบเก่า:

สิ่งที่คุณต้องการบรรลุสามารถทำได้ง่ายขึ้นโดยใช้ตัวช่วยผูกข้อมูลแบบสองทางของ 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'));

ง่ายใช่มั้ย

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

คุณสามารถใช้มิกซ์อินของคุณเองได้


ทำไมเราต้องผูก onchange เพื่อตั้งค่าสถานะ มันคือ ReactJS หลังจากนั้น!
Junaid Qadir

โปรดทราบว่าโซลูชันนี้เลิกใช้แล้ว
Philipp

6

คุณสามารถทำได้เช่นนี้:

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

ไม่ได้ทำงานให้ฉัน เห็นเครื่องมือสำหรับนักพัฒนา React การสร้างและการกำหนดค่าให้กับตัวแปร / วัตถุที่เรียกว่าอินพุตแทนที่จะเป็นอินพุต 1 / อินพุต 2
Gaurravs

1
@Gaurravs ใช่คุณพูดถูก ฉันต้องการที่จะเพิ่ม[]รอบinputเข้า setState นั่นทำให้ไดนามิคอลทรัพย์สินได้รับมอบหมาย
inostia

4

คุณสามารถใช้พิเศษReactแอตทริบิวต์ที่เรียกว่าrefแล้วตรงกับโหนด DOM ที่แท้จริงในonChangeเหตุการณ์โดยใช้ReactของgetDOMNode()ฟังก์ชั่น:

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

อย่างน้อยใน 0.13 this.refs ไม่มีคุณสมบัติ pref
ร้องไห้สะอึกสะอื้น

2
@usagidon - prevเป็นเพียงชื่อที่ฉันตั้งไว้ในrender()วิธีการ
Janusz Kacalak

2
ในฐานะของ React v0.14 event.target === this.refs.prevคุณก็สามารถทำได้ facebook.github.io/react/blog/2015/10/07/ …
XåpplI'-I0llwlg'I -

0

@Vigril Disgr4ce

เมื่อพูดถึงรูปแบบที่หลากหลายมันสมเหตุสมผลที่จะใช้คุณสมบัติหลักของ React: components

ในโครงการของฉันฉันสร้างองค์ประกอบ TextField ที่ใช้ prop value อย่างน้อยที่สุดและดูแลการจัดการพฤติกรรมทั่วไปของฟิลด์ข้อความอินพุต วิธีนี้คุณไม่ต้องกังวลเกี่ยวกับการติดตามชื่อฟิลด์เมื่ออัปเดตสถานะค่า

[...]

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

คุณสามารถติดตามมูลค่าของเด็กแต่ละคนinputโดยการสร้างแยกส่วนประกอบที่จัดการค่าของเดี่ยวInputField inputตัวอย่างเช่นInputFieldอาจเป็น:

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

ในตอนนี้ค่าของแต่ละค่าinputสามารถติดตามได้ภายในอินสแตนซ์ที่แยกจากกันของInputFieldส่วนประกอบนี้โดยไม่ต้องสร้างค่าแยกในสถานะของพาเรนต์เพื่อตรวจสอบองค์ประกอบย่อยแต่ละองค์ประกอบ


0

ฉันจะให้วิธีแก้ไขปัญหาที่ง่ายมาก สมมติว่าเรามีสองอินพุตusernameและpasswordแต่เราต้องการให้การจัดการของเราเป็นเรื่องง่ายและทั่วไปดังนั้นเราจึงสามารถใช้ซ้ำได้และไม่ต้องเขียนโค้ดสำเร็จรูป

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. ตัวสร้างของเราซึ่งเราต้องการบันทึกของเราusernameและpasswordเพื่อให้เราสามารถเข้าถึงได้อย่างง่ายดาย:

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

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

III. การจัดการที่น่าสนใจและ "ทั่วไป" ที่มีเพียงหนึ่งonChangeเหตุการณ์ขึ้นอยู่กับสิ่งนี้:

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

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


    event.preventDefault();
}

ให้ฉันอธิบาย:

1. เมื่อตรวจพบการเปลี่ยนแปลงonChange(event)จะเรียกว่า

2. จากนั้นเราจะได้รับชื่อพารามิเตอร์ของสนามและค่าของมัน:

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

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

3. ขึ้นอยู่กับพารามิเตอร์ชื่อเราได้รับค่าของเราจากรัฐในตัวสร้างและปรับปรุงด้วยค่า:

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

4. กุญแจสำคัญในการบันทึกที่นี่คือชื่อของฟิลด์จะต้องตรงกับพารามิเตอร์ของเราในสถานะ

หวังว่าฉันช่วยคนอย่างใด :)


0

รหัสสถานะของคุณควรเป็นชื่อเดียวกับฟิลด์ป้อนข้อมูลของคุณ จากนั้นคุณสามารถทำได้ในเมธอด handleEvent

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

-1

สวัสดีได้ปรับปรุงคำตอบssorallen คุณไม่จำเป็นต้องผูกฟังก์ชั่นเพราะคุณสามารถเข้าถึงอินพุตได้หากไม่มีมัน

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'));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.