React.js: идентификация различных входных данных с помощью одного обработчика onChange

97

Любопытно, как правильно подойти к этому:

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 для обработки каждого входа, но это не очень приятно. Аналогично, вы можете создать компонент только для отдельного ввода, но я хотел посмотреть, есть ли способ сделать это так.

Теги:

9 ответов

113

Я предлагаю придерживаться стандартных атрибутов HTML, таких как name в input Элементы для идентификации ваших входов. Кроме того, вам не нужно сохранять "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] и setState к этому. Такого рода работает, но, похоже, происходит некоторая задержка в обновлении объекта состояния.
  • 1
    «Вид задержки» - это обновление setState во время requestAnimationFrame (я так полагаю), так что игнорируйте это замечание
Показать ещё 9 комментариев
95

Вы можете использовать метод .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 или что-то подобное, оно сломается. Все ваши входные компоненты будут перерисованы при изменении одного значения.
  • 5
    Если вы измените реализацию handleChange на handleChange(name) { return event => this.setState({name: event.target.value}); } вы можете передать «ту же» функцию (не создаст новую функцию, как это делается с помощью .bind() Затем вы можете передать такую функцию: this.handleChange("input1")
Показать ещё 1 комментарий
27

Шаблоны событий 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})
}

Я использую что-то похожее на это в нескольких приложениях, и это довольно удобно.

  • 0
    довольно чистое решение. благодарю вас
11

Устаревшее решение

valueLink/checkedLink устарел от core 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

Вы даже можете реализовать свой собственный mixin

  • 0
    Почему мы должны связать onchange, чтобы установить состояние. Это ReactJS в конце концов!
  • 0
    Обратите внимание, что это решение устарело
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
    По крайней мере, в 0.13 this.refs не имеет свойства pref.
  • 2
    @usagidon - prev - это просто имя, которое я установил в методе render()
Показать ещё 1 комментарий
1

Вы также можете сделать это следующим образом:

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

render() {
    return (
        <div>
            <input type="text" onChange={e => this.handleChange('input1', e.target.value)} />
            <input type="text" onChange={e => this.handleChange('input2', e.target.value)} />
        </div>
    )
}
  • 0
    не работал для меня. видел инструменты разработки React. его создание и присвоение значений переменной / объекту, называемому input, вместо input1 / input2
  • 1
    @ Гаурравс, да, ты прав. Мне нужно было добавить [] вокруг input в setState. Это делает свойство динамически назначенным
Показать ещё 1 комментарий
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

Привет, улучшил 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'));
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} />;
}

[...]

Ещё вопросы

Сообщество Overcoder
Наверх
Меню