在 React 的 html 输入中在美分和美元之间进行转换



我的情况有点奇怪,我正在处理我们应用程序中的货币。在模型方面,我在发送到服务器之前将货币保存为美分,因为我不想处理服务器端的小数点。但是,在视图中,我希望显示正常货币而不是美分。

因此,我

有此输入字段,我在其中从美元中获取数据并将其更改为美分:

<input name="balance" type="number" step="0.01" min="0"
    placeholder="Balance in cents" onChange={this.handleUpdate}
    value={this.props.user.balance / 100} />

当输入值发生变化时,我会将其更改回美分,然后再将其发送到上游:

handleUpdate: function(e) {
  
  var value = e.target.value;
  
  // changing it back from cents to dollars
  value = parseFloat(value) * 100;
  
  // save back to the parent component managing the prop
  this.props.onUserUpdate(value);
  
}

这让我陷入了僵局,我无法输入小数点"。 让我演示一下:

  1. 输入框中的33 --> 在父状态下变得3300 -->在组件 prop 中恢复为33 - 一切都很好

  2. 输入框中的33.3 --> 在父状态下变得3330 -->在组件 prop 中恢复为33.3 - 一切都很好

  3. 输入框中的33. --> 在父状态下变得3300 -->在组件道具中恢复为33 - 这就是问题所在

正如您在案例 #3 中看到的那样,当用户首次输入"."时,这不会转换为与"." 相同的数字。

由于它是受控输入,因此基本上无法编写"."

我尝试将不受控制的元素与 defaultValue 一起使用,但是渲染组件时数量 prop 还没有准备好,所以它只是空的

http://jsfiddle.net/fpbhu1hs/

使用派生值的受控输入可能很棘手 - 如果您需要能够显示无效或其他奇怪的输入,那么......

  1. 始终将输入的value保存在其组件自己的state

    <input value={this.state.value} onChange={this.handleUpdate} // rest as above...
    
  2. getInitialState()中导出初始value

    getInitialState: function() {
      return {value: this.props.user.balance / 100}
    }
    
  3. 实现componentWillReceiveProps(nextProps)来检测 prop 的值何时从上面变化并重新导出状态值

    componentWillReceiveProps: function(nextProps) {
      if (this.props.user.balance != nextProps.user.balance) {
        this.setState({value: nextProps.user.balance / 100})
      }
    }
    

现在,当用户输入"33."时,您可以使用setState()存储其文本输入,然后回调到父级。

handleUpdate: function(e) {
  var value = e.target.value
  this.setState({value: value})
  this.props.onUserUpdate(parseFloat(value) * 100)
}

如果父级通过 props 传递回子级的值没有改变(在这种情况下3300 == 3300),那么componentWillReceiveProps()不会做任何事情。

工作片段:

<script src="http://fb.me/react-with-addons-0.12.2.js"></script>
<script src="http://fb.me/JSXTransformer-0.12.2.js"></script>
<div id="example"></div>
<script type="text/jsx;harmony=true">void function() { 'use strict';
var Parent = React.createClass({
  getInitialState() {
    return {cents: 3300}
  },
  
  _changeValue() {
    this.setState({cents: Math.round(Math.random() * 2000 + Math.random() * 2000)})
  },
  _onCentsChange(cents) {
    this.setState({cents})
  },
  render() {
    return <div>
      <p><strong>Cents:</strong> {this.state.cents.toFixed(0)} <input type="button" onClick={this._changeValue} value="Change"/></p>
      <Child cents={this.state.cents} onCentsChange={this._onCentsChange}/>
    </div>
  }
})
var Child = React.createClass({
  getInitialState() {
    return {dollars: this.props.cents / 100}
  },
  componentWillReceiveProps(nextProps) {
    if (this.props.cents != nextProps.cents) {
      this.setState({dollars: nextProps.cents / 100})
    }
  },
  _onChange(e) {
    var dollars = e.target.value
    this.setState({dollars})
    if (!isNaN(parseFloat(dollars)) && isFinite(dollars)) {
      this.props.onCentsChange(parseFloat(dollars) * 100)
    }
  },
  render() {
    return <div>
      <input type="number" step="0.01" min="0" value={this.state.dollars} onChange={this._onChange}/>
    </div>
  }
})
React.render(<Parent/>, document.querySelector('#example'))
}()</script>

我正在使用这个简单的解决方案来处理受控输入和十进制值。

  1. 在你的状态中创建两个 props,一个用于保存实际值,另一个用于保存字符串。

    constructor(props) {
        ....
        this.state = {
            myProperty: 1.42,
            myPropertyString: '1.42'
        }
    }
    
  2. 将输入值设置为字符串 1

    <input type="text"
           onChange={this.handleUpdate}
           value={this.state.myPropertyString}/>
    
  3. 句柄更新方法中,更新两个状态变量。

    handleUpdate(e) {
        this.setState({
            myProperty: parseFloat(e.target.value),
            myPropertyString: e.target.value
        });
    }
    

最新更新