我有点奇怪的情况,我在我的应用程序中处理货币.在模型方面,我在发送到服务器之前将货币保存为美分,因为我不想在服务器端处理小数点.
但是,在视图中,我希望显示正常货币而不是美分.
但是,在视图中,我希望显示正常货币而不是美分.
所以,我有这个输入字段,我从美元中获取数据并将其更改为美分:
<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); }
这让我陷入僵局,我无法输入小数点“.”让我来证明一下:
> 33在输入框中 – >在父状态下变为3300 – >在组件道具中回归33 – 一切都很好
> 33.3在输入框中 – >在父状态下变为3330 – >在组件道具中返回33.3 – 一切都很好
> 33.在输入框中 – >在父状态下变为3300 – >在组件道具中返回33 – 这就是问题所在
正如您在第3种情况中所看到的,当用户首次输入“.”时这不会转换回与“.”相同的数字.
由于它是一个受控输入,基本上没有办法写“.”
我已经尝试使用带有defaultValue的不受控制的元素,但是在渲染组件的时候,prop的数量还没准备好所以它只是空的
解决方法
使用派生值的受控输入可能很棘手 – 如果您需要能够显示无效或其他奇怪的输入,那么……
>始终将输入值保存在组件自身的状态中
<input value={this.state.value} onChange={this.handleUpdate} // rest as above...
>在getInitialState()中导出初始值
getInitialState: function() { return {value: this.props.user.balance / 100} }
>实现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>