Любопытно, как правильно подойти к этому:
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 для обработки каждого входа, но это не очень приятно. Аналогично, вы можете создать компонент только для отдельного ввода, но я хотел посмотреть, есть ли способ сделать это так.
Я предлагаю придерживаться стандартных атрибутов 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'));
Вы можете использовать метод .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
, вычисленный во время рендеринга, так как это рекомендуется делать.)
this.handleChange.bind(...)
создает новую функцию. В случае, если вы используете shouldComponentUpdate
с PureRenderMixin
или что-то подобное, оно сломается. Все ваши входные компоненты будут перерисованы при изменении одного значения.
handleChange
на handleChange(name) { return event => this.setState({name: event.target.value}); }
вы можете передать «ту же» функцию (не создаст новую функцию, как это делается с помощью .bind()
Затем вы можете передать такую функцию: this.handleChange("input1")
Шаблоны событий 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})
}
Я использую что-то похожее на это в нескольких приложениях, и это довольно удобно.
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
Вы можете использовать специальный атрибут 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>
...
}
prev
- это просто имя, которое я установил в методе render()
Вы также можете сделать это следующим образом:
...
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>
)
}
[]
вокруг input
в setState. Это делает свойство динамически назначенным
Вы можете отслеживать значение каждого дочернего элемента 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
без создания отдельных значений в родительском состоянии для контроля каждого дочернего компонента.
Привет, улучшил 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'));
@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} />;
}
[...]