I am implementing the following code based on the following page: https://facebook.github.io/react/docs/forms.html
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSubmit(event) {
event.preventDefault();
let data = {
isGoing: this.state.isGoing,
numberOfGuests: this.state.numberofGuests
}
/* Send data in ajax request here */
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Is going:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Number of guests:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Some questions I have about it:
render
function for every single character typed in or deleted. To me this makes little sense.this.setState()
and actually accessing the state with this.state.numberOfGuests
does this mean that this code may end up grabbing the state before it has been set? If so, why is this code being suggested in the official React docs? If not, why not?Regarding point number two, then yes it is logically possible that handleSubmit
could run before the state update in handleInputChanged
has completed. The reason this isn't mentioned in the React docs, or is generally a concern for anyone is because the setState
function runs really quickly. As an experiment I made a codepen to determine the average time taken for setState to run. It seems to take in the order of around 0.02 milliseconds. There is no way someone can change their input, then submit the form in less than that time. In fact, the e.preventDefault()
call in handleSubmit
takes nearly a quarter of that time anyway.
If you have a situation where it is absolutely crucial that setState
has completed before continuing, then you can use a callback function to setState
, e.g.
this.setState({
colour: 'red'
}, () => {
console.log(this.state.color)
});
Then red
will always be logged, as opposed to the following where the previous value may be logged.
this.setState({
colour: 'red'
});
console.log(this.state.color);
Very good questions! Here's my take on them:
1. Controlled or Uncontrolled - that is the question
You don't have to use controlled form elements. You can use uncontrolled and grab the values as you suggest in your onFormSubmit handler by doing something like event.isGoing.value
- plain ole JavaScript (or use refs as some React articles suggest). You can even set a default value with uncontrolled no problem by using, you guessed it, defaultValue={myDefaultValue}
.
The above being said, one reason to use controlled components would be if you're looking to give real time feedback while the user is still typing. Say you need to do an autocomplete lookup or provide validation like password strength. Having a controlled component that re-renders with the values in the state makes this super simple.
2. this.setState()
asynchronous issues?
[Maybe incorrectly,] I view internally component state updates more like a queue system. No call to this.setState()
will be lost and shouldn't overwrite another one when dealing with synchronous code. However, there could be a time where a render is running behind a setState update, but it will eventually have and render the most recent value. Ex: the user types 3 characters, but they only see 2, then a short time later they should see the third. So, there was a point in time where the read to this.state
read an "old" value, but it was still eventually updated. I hope I'm making sense here.
Now, I mention synchronous code above because with asynchronous code (like with AJAX) you could potentially introduce a race condition where this.setState()
overwrites a newer state value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With