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


148

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

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


Привет, хороший вопрос,
Аашик Ахмед

Ответы:


166

Я предлагаю придерживаться стандартных атрибутов 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'));

4
Сначала я пытался сделать это, но setState ({e.target.name ... не работает - это синтаксическая ошибка. Вы должны создать временный объект с obj [e.target.name] и setState для этого. Это работает, но, похоже, есть какая-то задержка в обновлении объекта состояния.
T3db0t

1
«Вид задержки» - это обновление setState во время requestAnimationFrame (я предполагаю), поэтому игнорируйте это замечание
T3db0t

24
@ T3db0t Этот синтаксис ES6 работает:this.setState({ [e.target.name]: e.target.value });
XåpplI'-I0llwlg'I -

2
Использование связывания - лучший подход. Этот подход не работает, если вы прикрепляете обработчик onChange к элементу без свойства name, например div.
ericgrosse

3
Привязка @ericgrosse в этом случае не лучше, так как вы создаете много ненужных функций. Кроме того, вы можете использовать атрибут data- или что-то еще в элементе другого типа, если это необходимо
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(...)создающее новую функцию. Если вы используете shouldComponentUpdatewith PureRenderMixinили что-то подобное, он сломается. Все ваши входные компоненты будут повторно отображены при изменении одного значения.
zemirco 01

5
Если вы измените реализацию handleChangeна, handleChange(name) { return event => this.setState({name: event.target.value}); }вы можете передать «ту же» функцию (не будет создавать новую функцию, как это делается с помощью .bind()Then, вы можете передать такую ​​функцию:this.handleChange("input1")
Andreyco

1
Я думаю, также важно упомянуть, что природа setState заключается в том, что нельзя будет получить текущее состояние в функции handChange, а будет использовать предыдущее состояние, например, this.state.input1. Правильный подход заключается в создании обратного вызова, например, this.setState(change, function () { console.log(this.state.input1); );reference: stackoverflow.com/questions/30782948/…
Чарли-Гринман,

Привет, @flatjaf, это неправильный подход, так как он теряет функцию при рендеринге
Аашик Ахмед

Этот ответ устарел. Кто-нибудь, пожалуйста, отредактируйте это. Я больше не использую React, поэтому не уверен, что сейчас будет правильным ответом.
fiatjaf

40

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

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


Почему мы должны связывать onchange для установки состояния. В конце концов, это 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.
Благодаря

4

Вы можете использовать специальный Reactатрибут , refа затем сопоставить узлы реального DOM в onChangeслучае использования React«s 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()методе
Януш Кацалак

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, которые принимают как минимум свойство 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. На основе параметра 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.