I'm trying to create a React functional component that be able to format a float number into a currency number (using comma and dot). My approach is use onBlur event for start to transform the number after the input loses focus, because when I use onChange event, the component recalculate the new format when I press any character key, so I can't delete the last 2 zero characters when I use this event. With my current approach, I can transform the number and show in other HTML element, like a span, but I have not been able to replace the old number in the input with the new formatted number.
This is the code of my component:
import { useEffect, useState } from 'react';
import './InputCurrency.css';
function InputCurrency(props) {
const [currencyNumber, setCurrencyNumber] = useState('');
useEffect(() => {
console.log(currencyNumber);
}, [currencyNumber]);
const formatNumber = (num) => {
setCurrencyNumber(parseFloat(num).toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'));
}
return (
<div>
<input
id="inputNumber"
type="number"
defaultValue={currencyNumber}
onBlur={e => formatNumber(e.target.value)}
placeholder='0.00'
/>
</div>
);
}
export default InputCurrency;
The defaultValue
prop is used to set the initial value of an input field when it is rendered. It is only used once, during the initial render, and does not update automatically when the component's state changes. In your case, if you use defaultValue
, the input field will not reflect the formatted currency number because the defaultValue
will not be updated when currencyNumber
changes.
So you need value
and onChange
to control the value of an input field by linking it to a state variable. It allows you to create a controlled component, where the value of the input field is controlled by React state.
And in your formatNumber function, I have modified the logic so it can handle the next input, otherwise it will throw an error since parseFloat
cannot parse value like "5,535,555.00"
const InputCurrency = () => {
const [currencyNumber, setCurrencyNumber] = useState('');
const formatNumber = (num: string) => {
const isNumber = parseFloat(num.replace(/,/g, ''));
if(isNaN(isNumber)) {
setCurrencyNumber('0.00')
} else {
const formattedNumber = isNumber.toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
setCurrencyNumber(formattedNumber);
}
}
useEffect(() => {
console.log(currencyNumber);
}, [currencyNumber]);
return (
<div>
<input
id="inputNumber"
type="text"
value={currencyNumber}
onBlur={(e) => formatNumber(e.target.value)}
onChange={(e) => setCurrencyNumber(e.target.value)}
placeholder='0.00'
/>
</div>
);
}