Reactjs Form Validation When State Is Not Immediately Updated
Solution 1:
When you want to derive data from state, the simplest way to do it is right before you actually need it. In this case, you just need it in render.
validate: function (data) {
var validation_errors = validate(data, constraints);
if(validation_errors){
return validation_errors;
}
return {};
},
render: function() {
var errors = this.validate(this.state.data);
...
<Control label="Email" error={errors.email}>
...
State should very rarely be used as a derived data cache. If you do want to derive data when setting state, be very careful, and just make it an instance property (e.g. this.errors
).
Because the setState callback actually causes an additional render cycle, you can immutably update data instead, and pass it to this.validate (see how I made validate not depend on the current value of this.state.data in the above code?).
Based on your current changeState, it'd look like this:
changeState: function () {
var update = React.addons.update;
var getValue = function(ref){ returnthis.refs[ref].getDOMNode().value }.bind(this);
vardata = update(this.state.data, {
email: {$set: getValue('email')},
password: {$set: getValue('password')},
password_confirmation: {$set: getValue('password_confirmation')}
});
this.errors = this.validate(data);
this.setState({data: data});
},
// we'll implement this because now it's essentially free
shouldComponentUpdate: function(nextProps, nextState){
returnthis.state.data !== nextState.data;
}
In the comments/answers people are saying that errors should be in state, and that's sometimes true. When you can't implement render without the errors being in state, they should be in state. When you can implement by deriving existing data from state, that means that putting it in state would be redundant.
The problem with redundancy is it increases the likelihood of very difficult to track down bugs. An example of where you can't avoid keeping the data as state is with async validation. There's no redundancy, because you can't derive that from just the form inputs.
I made a mistake of not updating the state of errors too. – blushrt
This is exactly why.
Solution 2:
Why wouldn't you just validate the data before you set the state? The errors are also state, so it would be logical to set them in the same fashion as the rest of the state.
changeState: function () {
vardata = {
email: this.refs.email.getDOMNode().value,
password: this.refs.password.getDOMNode().value,
password_confirmation: this.refs.password_confirmation.getDOMNode().value
},
errors = validate(data, constraints) || {};
this.setState({
data: data,
errors: errors
});
},
Solution 3:
A simple solution would be to check the validity of the data in the changeState
method instead.
The other solution would be to pass a callback to setState
:
In addition, you can supply an optional callback function that is executed once
setState
is completed and the component is re-rendered.[...]
setState()
does not immediately mutatethis.state
but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.There is no guarantee of synchronous operation of calls to
setState
and calls may be batched for performance gains.
Post a Comment for "Reactjs Form Validation When State Is Not Immediately Updated"