Reputation: 193
I'm building a fee calculator with React-Native, and I have multiple input fields that variables for my calculation are set with.
Everything works well when the input fields have correct values however if the user hits backspace on what they have previously input and then try to calculate profit with an empty field the total shows up as NaN.
Here is my code so far:
this.state = {
text: '',
soldPrice: 0,
shippingCost: 0,
shippingCharge: 0,
itemCost: 0,
profit: 0,
paypalFee: 0.30,
paypalFeePercentage: 0.029,
ebayFee: 0.1
};
}
calculateProfit = () => {
const { soldPrice, shippingCost, shippingCharge, itemCost,
paypalFee, ebayFee, paypalFeePercentage
} = this.state;
let sp = parseFloat(soldPrice);
const sc = parseFloat(shippingCost);
const sCharge = parseFloat(shippingCharge);
const ic = parseFloat(itemCost);
const pf = parseFloat(paypalFee);
const ef = parseFloat(ebayFee);
const pfp = parseFloat(paypalFeePercentage);
// sp = soldPrice, sc = shippingCost,
// sCharge = shippingCharge, ic = itemCost,
// pf = paypalFee, ef = ebayFee, pfp = paypalFeePercentage, c = calculation
const calculation = sp - sp * pfp -
pf
- sp * ef - sc
- ic;
sp += sCharge;
if (!this.state.itemCost) {
this.setState({ itemCost: 0 });
}
let i;
// if profit is more than 10 than the profit will be displayed as 00.00
// otherwise it will be displayed as 0.00
if (calculation > 1000) {
i = 6;
} else if (calculation > 100) {
i = 5;
} else if (calculation > 10) {
i = 4;
}
const roundedNumber = calculation.toPrecision(i);
this.setState({
profit: roundedNumber
});
}
render() {
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Efees</Text>
</View>
<View style={styles.blocks}>
<View style={styles.inputs}>
<Text style={styles.inputText}>Sold Price</Text>
<TextInput
underlineColorAndroid='transparent'
style={styles.TextInputStyle}
placeholder='0.00'
keyboardType={'numeric'}
value={this.state.soldPrice}
onChangeText={(soldPrice) => this.setState({ soldPrice })}
/>
</View>
<View style={styles.inputs}>
<Text style={styles.inputText}>Shipping Charge</Text>
<TextInput
underlineColorAndroid='transparent'
style={styles.TextInputStyle}
placeholder='0.00'
keyboardType={'numeric'}
value={this.state.shippingCharge}
onChangeText={(shippingCharge) => this.setState({ shippingCharge })}
/>
</View>
<View style={styles.inputs}>
<Text style={styles.inputText}>Shipping Cost</Text>
<TextInput
underlineColorAndroid='transparent'
style={styles.TextInputStyle}
placeholder='0.00'
keyboardType={'numeric'}
value={this.state.shippingCost}
onChangeText={(shippingCost) => this.setState({ shippingCost })}
/>
</View>
<View style={styles.inputs}>
<Text style={styles.inputText}>Item Cost</Text>
<TextInput
underlineColorAndroid='transparent'
style={styles.TextInputStyle}
placeholder='0.00'
keyboardType={'numeric'}
value={this.state.itemCost}
onChangeText={(itemCost) => this.setState({ itemCost })}
/>
</View>
<View style={styles.inputs}>
</View>
</View>
<TouchableOpacity
style={styles.calcButton}
onPress={this.calculateProfit}
>
<Text style={styles.calcText}>Calculate </Text>
</TouchableOpacity>
<Text>{`Profit: $${this.state.profit}`}</Text>
</View>
);
}
}
Upvotes: 2
Views: 3393
Reputation: 30390
The issue here is caused by parseFloat()
returning Number.NaN
when attempting to parse an empty string:
/* Parse a valid value */
console.log( parseFloat('1.2') , '===', 1.2 );
/* Parse an empty string yields NaN */
console.log( parseFloat('') , '===', Number.NaN );
When a Number.NaN
is introduced into the arithmetic of your subsequent calculation by one or more variables, the value of calculation
will be Number.NaN
:
const sp = 1,
pfp = 1,
ef = 1,
pf = 1,
sc = 1,
ic = Number.NaN;
const calculation = sp - sp * pfp - pf - sp * ef - sc - ic;
console.log(calculation);
There are many ways to resolve this issue - a simple method that requires minimal change with your current code would be as follows:
calculateProfit = () => {
const {
soldPrice,
shippingCost,
shippingCharge,
itemCost,
paypalFee,
ebayFee,
paypalFeePercentage
} = this.state;
/*
Define helper function that recovers a 0 as a default value
if "non-a-number" results from parseFloat
*/
const safeParseFloat = (str) => {
const value = Number.parseFloat(str);
return Number.isNaN(value) ? 0 : value;
}
/*
Use locally defined helper to safely parse strings while also
accounting form empty string mapping to 0
*/
let sp = safeParseFloat(soldPrice);
const sc = safeParseFloat(shippingCost);
const sCharge = safeParseFloat(shippingCharge);
const ic = safeParseFloat(itemCost);
const pf = safeParseFloat(paypalFee);
const ef = safeParseFloat(ebayFee);
const pfp = safeParseFloat(paypalFeePercentage);
const calculation = sp - sp * pfp - pf - sp * ef - sc - ic;
sp += sCharge;
if (!this.state.itemCost) {
this.setState({
itemCost: 0
});
}
let i;
// if profit is more than 10 than the profit will be displayed as 00.00
// otherwise it will be displayed as 0.00
if (calculation > 1000) {
i = 6;
} else if (calculation > 100) {
i = 5;
} else if (calculation > 10) {
i = 4;
}
const roundedNumber = calculation.toPrecision(i);
this.setState({
profit: roundedNumber
});
}
Upvotes: 6