在React中的html输入中转换美分和美元

时间:2015-01-21 16:58:15

标签: javascript reactjs

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

所以,我有这个输入字段,我从美元中获取数据并将其更改为美分:

<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);

}

这让我陷入僵局,我无法输入小数点&#34;。&#34;让我演示一下:

    输入框中的
  1. 33 - &gt;在父状态中变为3300 - &gt;在组件道具中返回33 - all good

  2. 输入框中的
  3. 33.3 - &gt;在父状态中变为3330 - &gt;在组件道具中返回33.3 - all good

  4. 输入框中的
  5. 33. - &gt;在父状态中变为3300 - &gt;在组件道具中返回33 - 这是问题

  6. 正如您在第3种情况中所见,当用户第一次进入&#34;。&#34;这并没有用&#34;。&#34;

    转换回相同的数字

    由于它是受控制的输入,因此基本上没有办法写作&#34;。&#34;

    我尝试使用defaultValue不受控制的元素,但是在渲染组件的时候,prop的数量尚未准备就绪,因此它只是空的

    http://jsfiddle.net/fpbhu1hs/

2 个答案:

答案 0 :(得分:10)

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

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

    <input value={this.state.value} onChange={this.handleUpdate} // rest as above...
    
  2. 导出value

    中的初始getInitialState()
    getInitialState: function() {
      return {value: this.props.user.balance / 100}
    }
    
  3. 实现componentWillReceiveProps(nextProps)以检测道具的值何时从上方变化并重新获得状态值

    componentWillReceiveProps: function(nextProps) {
      if (this.props.user.balance != nextProps.user.balance) {
        this.setState({value: nextProps.user.balance / 100})
      }
    }
    
  4. 现在,当用户输入“33.”时,您使用setState()存储他们的文字输入,然后回拨给父母。

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

    如果父级然后通过道具传回给孩子的值没有改变(在这种情况下为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 :(得分:1)

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

  1. 在您的州创建两个道具,一个用于保存实际值,另一个用于保存字符串。

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

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

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