React Component and Invalid Input

2019-04-12 04:28发布

I have the following react component:

var App = React.createClass({
    getInitialState: function() {
        return {value: 4.5}
    },
    change: function(event) {
        this.setState({value: parseFloat(event.target.value)});
    },
    render: function() {
        return <input type="number" value={this.state.value} onChange={this.change}/>;
    }
});

React.render(<App/>, document.body);

You can see it here: http://jsfiddle.net/2hauj2qg/

The problem is that if I want to type in a number like: "4.7". When the user enters, "4.", it becomes "4", due to being converted to a float in back. But this interrupts what the user was typing. What's the recommended way of solving this problem?

4条回答
我命由我不由天
2楼-- · 2019-04-12 05:24

Remove the parseFloat and your string won't be cast to a number?

    change: function(event) {
        this.setState({value: event.target.value});
    }

http://jsfiddle.net/2hauj2qg/1/

查看更多
祖国的老花朵
3楼-- · 2019-04-12 05:29

If it doesn't make sense to do anything with the number until they're done typing and you follow the standard way of raising an event to signal changed data, you can accomplish it with the following:

var MyComponent = React.createClass({
    getInitialState: function() {
        return {value: 4.5};
    },
    change: function(event) {
        this.setState({value: event.target.value});
    },
    blur: function(event) {
        this.props.onChange({value: parseFloat(event.target.value)});
    },
    render: function() {
        return <input type="number" value={this.state.value} onBlur={this.blur} onChange={this.change}/>;
    }
});

React.render(<MyComponent/>, document.body);

It doesn't make too much sense in this isolated example, but if you assume someone is using MyComponent and that they give it an onChange callback, then this works nicely. You get the benefits of a native input control but still return (through the callback) the number as an actual float.

查看更多
戒情不戒烟
4楼-- · 2019-04-12 05:32

As imjared mentioned, it's because you're using parseFloat

this.setState({value: parseFloat(event.target.value)});

Instead, you may wish to only allow digits and the decimal. It stays stored as a string and never changes their input, but they're prevented from typing things like letters and spaces.

var nonNumericRegex = /[^0-9.]+/g;

this.setState({value: event.target.value.replace(nonNumericRegex, "")});

To allow negative numbers you need to do this:

this.setState({
    value: event.target.value
        .replace(nonNumericRegex, "")
        .replace(/^(-.*?)-/g, "$1")
});

To enforce a leading dollar sign and no more than two decimals, and if the first character (after the $) is the decimal, prefix it with 0.

this.setState({
    value: "$" + event.target.value
        .replace(nonNumericRegex, "")
        .replace(/(\.\d\d)\d+/g, "$1")
        .replace(/^\./g, "0.")
})
查看更多
够拽才男人
5楼-- · 2019-04-12 05:32

What about writing a small component that will handle string values and pass only legal float values to the listeners ?

class NumberInput extends React.Component<{ onChange: (n: number) => void, value: number }, { value: number }> {

  constructor(props: { onChange: ((n: number) => void); value: number }, context: any) {
    super(props, context);
    this.state = {
      value: props.value || 0
    };
  }

  handleInputChange = (e) => {
    const value = e.target.value;
    this.setState({
      value: value
    });
    if (this.props.onChange) {
      const floatValue = parseFloat(value);
      if (!isNaN(floatValue)) {
        this.props.onChange(floatValue)
      }
    }
  };

  componentWillReceiveProps(newProps) {
    this.setState({
      value: newProps.value
    })
  }

  render() {
    return (
      <Input step="0.1" value={this.state.value} onChange={this.handleInputChange} type="number"/>
    )
  }
}
查看更多
登录 后发表回答