React.js: Ідентифікація різних входів за допомогою одного обробника onChange


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

Очевидно, ви можете створити окремі функції handleChange для обробки кожного різного входу, але це не дуже приємно. Так само ви можете створити компонент лише для індивідуального введення, але я хотів подивитися, чи є спосіб зробити це так.

Відповіді:


163

Я пропоную дотримуватися стандартних атрибутів HTML, наприклад nameна inputElements, щоб визначити свої дані. Крім того, вам не потрібно зберігати "total" як окреме значення у державі, оскільки воно можна складати, додаючи інші значення у вашому штаті:

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 ... не працює - це синтаксична помилка. Ви повинні зробити тимчасовий об’єкт з obj [e.target.name] і встановитиState на це. Цей вид працює, але, мабуть, є якась затримка оновлення державного об'єкта
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

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.state.input1. Правильним підходом буде створення зворотного дзвінка, такого як 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, тому що це збиває з пантелику деяких користувачів. Ця відповідь не буде працювати, якщо ви використовуєте останню версію 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

Ви навіть можете реалізувати свій власний міксин


Чому ми повинні прив’язати зміну, щоб встановити стан. Це ReactJS після закінчення!
Джунайд Кадір

Зауважте, що це рішення застаріле
Філіп

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. його створення та призначення значень змінної / об'єкту, що називається input, замість input1 / input2
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 у цього файлу.refs не є властивість pref.
клубу

2
@usagidon - prevце лише ім’я, яке я встановив у render()методі
Януш Качалак

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: компоненти.

У своїх проектах я створюю компоненти TextField, які мають мінімальну підтримку значень, і це турбується про обробку загальної поведінки вхідного текстового поля. Таким чином, вам не потрібно турбуватися про відстеження імен полів під час оновлення стану значення.

[...]

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, але ми хочемо , щоб наші ручки , щоб бути легким і універсальним, так що ми можемо використовувати його і не писати код шаблонний.

І.Наша форма:

                <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.Залежно від параметра name, ми отримуємо наше значення зі стану в конструкторі та оновлюємо його значенням:

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'));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.