I've run into this problem a few times, and I'm looking for the "react way" to solve this.
The Problem
A number field is temporarily invalid while the user is typing. For example: "-45" is "-" and "2.3" is "2.". The simplest validation example is just to parseFloat on the value. Here's a working example: http://jsfiddle.net/h55kruca/6/. I'm looking for a way to validate onBlur instead of onChange, or something similar that achieves this.
Here's the JS in the example:
var App = React.createClass({
getInitialState: function() {
return {number: 0}
},
handleNumberChange: function(e) {
var val = parseFloat(e.target.value);
this.setState({number: val});
},
render: function() {
return (
<Editor number={this.state.number}
onNumberChange={this.handleNumberChange}
/>
);
}
});
var Editor = React.createClass({
render: function() {
return (
<form className="reactForm" >
<input type='text'
value={this.props.number}
onChange={this.props.onNumberChange} />
<span>{this.props.number}</span>
</form>
);
}
});
Note that the validation (parseFloat
in this case) is happening in a parent or grandparent (and is ultimately stored on the server) and the Editor's props.number
changes by user input or from refreshed data from the server. This is the reason for a controlled component.
Approach #0
I tried using onBlur instead of onChange, and react gave me this warning: Warning: Failed form propType: You provided a 'value' prop to a form field without an 'onChange' handler. This will render a read-only field. If the field should be mutable use 'defaultValue'. Otherwise, set either 'onChange' or 'readOnly'.
Approach #1
Store a temporary "number" state that is actually a string. Use that for whatever the user types in the input until onBlur. I don't like this because of the amount of code needed to achieve something so simple. I would probably end up creating a wrapper around each input element (painful to me).
Approach #2
Wrap the input in a component that uses shouldComponentUpdate to stop updates until onBlur. This again requires a wrapper around every input.
Approach #3
Make the input an uncontrolled component by taking out the value=
. I haven't fully thought this through but I think I'll very quickly miss the features of the controlled component. If there was a way to switch between controlled and uncontrolled onFocus and onBlur maybe that's my answer.
Your Solution
There must be a simple way to solve this, or at least something in development within the react community, I just can't find anything. How have you solved this?