diff --git a/source/components/CurrencyInput/CurrencyInput.js b/source/components/CurrencyInput/CurrencyInput.js index 0203aaef0..898f50d7b 100644 --- a/source/components/CurrencyInput/CurrencyInput.js +++ b/source/components/CurrencyInput/CurrencyInput.js @@ -24,8 +24,8 @@ let currencyFormat = language => ({ class CurrencyInput extends Component { state = { - value: this.props.value || '', - valueHasChanged: false, + value: this.props.value, + initialValue: this.props.value } onChange = this.props.debounce @@ -50,6 +50,14 @@ class CurrencyInput extends Component { this.onChange(event) } + // See https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#alternative-1-reset-uncontrolled-component-with-an-id-prop + static getDerivedStateFromProps({ value }, { initialValue }) { + if (value !== initialValue) { + return { value, initialValue: value } + } + return null + } + render() { let forwardedProps = omit( ['onChange', 'defaultValue', 'language', 'className', 'value'], @@ -62,6 +70,9 @@ class CurrencyInput extends Component { decimalSeparator } = currencyFormat(this.props.language) + // We display negative numbers iff this was the provided value (but we allow the user to enter them) + const valueHasChanged = this.state.value !== this.state.initialValue + return (
{ - this.setState({valueHasChanged: true, value}) - this.value = value.toString().replace(/^\-/,'') + this.setState({ value }) + this.value = value.toString().replace(/^\-/, '') this.handleNextChange = true }} onChange={this.handleChange} - value={this.state.value.toString() + value={(this.state.value || '') + .toString() .replace('.', decimalSeparator)} /> {!isCurrencyPrefixed && <> €} diff --git a/source/components/CurrencyInput/CurrencyInput.test.js b/source/components/CurrencyInput/CurrencyInput.test.js index cdee61c95..cd492910e 100644 --- a/source/components/CurrencyInput/CurrencyInput.test.js +++ b/source/components/CurrencyInput/CurrencyInput.test.js @@ -64,7 +64,7 @@ describe('CurrencyInput', () => { it('should not call onChange while the decimal part is being written', () => { let onChange = spy() - const input = getInput() + const input = getInput() input.simulate('change', { target: { value: '111,', focus: () => {} } }) expect(onChange).not.to.have.been.called }) @@ -105,25 +105,23 @@ describe('CurrencyInput', () => { clock.restore() }) - it('should initialize with value of the storeValue prop', () => { - const input = getInput() - expect(input.prop('value')).to.eq(1) + it('should initialize with value of the value prop', () => { + const wrapper = shallow() + expect(wrapper.state('value')).to.eq(1) }) - it('should update its value if the storeValue prop changes', () => { - const wrapper = shallow() - wrapper.setProps({ storeValue: 2 }) + it('should update its value if the value prop changes', () => { + const wrapper = shallow() + wrapper.setProps({ value: 2 }) expect(wrapper.state('value')).to.equal(2) }) - it('should not update state if the storeValue is the same as the current input value', () => { - const wrapper = shallow( - {}} /> - ) + + it('should not call onChange the value is the same as the current input value', () => { + let onChange = spy() + const wrapper = mount( {}} />) const input = wrapper.find('input') - input.simulate('change', { target: { value: '2000' } }) - const state1 = wrapper.state() - wrapper.setProps({ storeValue: '2000' }) - const state2 = wrapper.state() - expect(state1).to.equal(state2) + input.simulate('change', { target: { value: '2000', focus: () => {} } }) + wrapper.setProps({ value: '2000' }) + expect(onChange).not.to.have.been.called }) }) diff --git a/source/components/TargetSelection.js b/source/components/TargetSelection.js index 2648af962..a857f66e3 100644 --- a/source/components/TargetSelection.js +++ b/source/components/TargetSelection.js @@ -7,7 +7,7 @@ import withLanguage from 'Components/utils/withLanguage' import withSitePaths from 'Components/utils/withSitePaths' import { encodeRuleName } from 'Engine/rules' import { compose, isEmpty, isNil, propEq } from 'ramda' -import React, { Component, PureComponent, useRef } from 'react' +import React, { Component, PureComponent } from 'react' import { withTranslation } from 'react-i18next' import { connect } from 'react-redux' import { Link } from 'react-router-dom'