Reputation: 37068
So look at this code below for our example, a simple 2-way data-binding on an input field connecting the field to a property inputValue
.
But say you have a more complex page with 30 or more inputs. Are you supposed to write 30+ onChange
handlers in the class, all with different names corresponding to the inputs like onNameChange
, onEmailChange
, onPhoneChange
, and so on? Is there no neater, more implicit way to bind inputs than what I have below here?
React.createClass({
getInitialState() {
inputValue: ''
},
render() {
return (
<input
type='text'
value={this.state.inputValue}
onChange={this.onChange} />
);
},
onChange(e) {
this.setState({ inputValue: e.target.value });
}
});
Edit: I suppose I could do this and avoid writing handlers on the class:
<input onChange={ e => this.setState({firstName: e.target.value}) } />
Is that kosher?
Upvotes: 4
Views: 3800
Reputation: 770
React docs has your solution:
https://facebook.github.io/react/docs/forms.html#handling-multiple-inputs
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleInputChange(event) {
const target = event.target;
this.setState({
[target.name]: target.value
});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input name="name" type="text" value={this.state.name} onChange={this.handleInputChange} />
</label>
<label>
Email:
<input name="email" type="text" value={this.state.email} onChange={this.handleInputChange} />
</label>
<label>
Pet:
<input name="country" type="text" value={this.state.country} onChange={this.handleInputChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Upvotes: 3
Reputation: 281726
The neater way would be to have a single onChange
handler and pass on the id to it, and store the value with that id. Your solution will look like
React.createClass({
getInitialState() {
},
onChange(e, type) {
this.setState({[type]: e.target.value})
},
render() {
return (
<input
type='text'
value={(this.state.inputValue)? this.state.inputValue: ''}
onChange={this.onChange.bind(this, 'inputValue')} />
<input
type='text'
value={(this.state.emailValue)? this.state.emailValue: ''}
onChange={this.onChange.bind(this, 'emailValue')} />
);
},
onChange(e) {
this.setState({ inputValue: e.target.value });
}
});
The value is given with a ternary operator expression
because initially the state is not defined and hence we will get a warning that input is trying to change the uncontrolled input to controlled.
The other way is to have the handler inline like
onChange={ e => this.setState({inputValue: e.target.value}) }
but say you have 30 inputs you need to define their initial state and let it set its value like above, only difference being the value being assigned to it should be with the expression as shown in the first example
The other way to assign value to the input as @MayankShukla suggessted will be
value = {this.state.inputValue || ''}
with getInitialState looking like
getInitialState() {
return {}
},
Upvotes: 1