In the React docs it says that in a controlled component, "the React state be the “single source of truth”". This seems to be true except in cases with leading zeros. In the below example, you can see that the input is controlled, but in a case with leading zeros, the input value doesn't always match the state value.
The Test
Type leading zeros, so the value is something like 0010
.
You can see that the value in state
is an integer 10
, but the input shows 0010
.
My first thought was this was because the component doesn't actually re-render, which is true. There's no state change between 10
and 10
, so no new render. This is confirmed since we don't see the 'render' console.log firing.
So let's make sure we change the value. Add a 2
to change 0010
to 00102
. The value in state is now 102
, we confirm the component re-renders...but still the leading zeros persist in the input.
This seems inconsistent as I would expect the value in the input to always match the value in state exactly. Why is this and what is a reliable way to trim leading zeros from a number input?
// LEADING ZEROS INPUT TEST
// Step 1: type 0s into the input followed by any other digits
// Step 2: see that console log and val in `p` do not have leading 0's and input val does
const {useState} = React;
const App = () => {
const [val, setVal] = useState(10);
const handleChange = (evt) => {
const strVal = evt.currentTarget.value;
console.log('string', strVal, typeof strVal);
const intVal = parseInt(strVal, 10) || 0; // || 0 bc '' returns NaN
console.log('int', intVal, typeof intVal);
setVal(intVal);
}
console.log('render', val);
return (
<div>
<p>{val}</p>
<input
type="number"
value={val}
onChange={handleChange}
/>
</div>
)
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>