Curious what the right way to approach this is:
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'));
Obviously you could create separate handleChange functions to handle each different input, but that's not very nice. Similarly you could create a component just for an individual input, but I wanted to see if there's a way to do it like this.
This question is related to
javascript
reactjs
jsx
The key of your state should be the same as the name of your input field. Then you can do this in the handleEvent method;
this.setState({
[event.target.name]: event.target.value
});
The onChange
event bubbles... So you can do something like this:
// A sample form
render () {
<form onChange={setField}>
<input name="input1" />
<input name="input2" />
</form>
}
And your setField method might look like this (assuming you're using ES2015 or later:
setField (e) {
this.setState({[e.target.name]: e.target.value})
}
I use something similar to this in several apps, and it's pretty handy.
You can use a special React
attribute called ref
and then match the real DOM nodes in the onChange
event using React
's getDOMNode()
function:
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>
...
}
You can use the .bind
method to pre-build the parameters to the handleChange
method.
It would be something like:
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'));
(I also made total
be computed at render time, as it is the recommended thing to do.)
Hi have improved ssorallen answer. You don't need to bind function because you can access to the input without it.
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'));
You can track the value of each child input
by creating a separate InputField
component that manages the value of a single input
. For example the InputField
could be:
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} />)
}
})
Now the value of each input
can be tracked within a separate instance of this InputField
component without creating separate values in the parent's state to monitor each child component.
You can also do it like this:
...
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>
)
}
I will provide really simple solution to the problem.
Suppose we have two inputs username
and password
,but we want our handle to be easy and generic ,so we can reuse it and don't write boilerplate code.
I.Our form:
<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.Our constructor ,which we want to save our username
and password
,so we can access them easily:
constructor(props) {
super(props);
this.state = {
username: '',
password: ''
};
this.onSubmit = this.onSubmit.bind(this);
this.onChange = this.onChange.bind(this);
}
III.The interesting and "generic" handle with only one onChange
event is based on this:
onChange(event) {
let inputName = event.target.name;
let value = event.target.value;
this.setState({[inputName]:value});
event.preventDefault();
}
Let me explain:
1.When a change is detected the onChange(event)
is called
2.Then we get the name parameter of the field and its value:
let inputName = event.target.name; ex: username
let value = event.target.value; ex: itsgosho
3.Based on the name parameter we get our value from the state in the constructor and update it with the value:
this.state['username'] = 'itsgosho'
4.The key to note here is that the name of the field must match with our parameter in the state
Hope I helped someone somehow :)
valueLink/checkedLink
are deprecated from core React, because it is confusing some users. This answer won't work if you use a recent version of React. But if you like it, you can easily emulate it by creating your own Input
component
What you want to achieve can be much more easily achieved using the 2-way data binding helpers of 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'));
Easy right?
http://facebook.github.io/react/docs/two-way-binding-helpers.html
You can even implement your own mixin
@Vigril Disgr4ce
When it comes to multi field forms, it makes sense to use React's key feature: components.
In my projects, I create TextField components, that take a value prop at minimum, and it takes care of handling common behaviors of an input text field. This way you don't have to worry about keeping track of field names when updating the value state.
[...]
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} />;
}
[...]
Source: Stackoverflow.com