I am trying to create a basic square foot calculator using React State and am running into something I've not seen before. I'm sure it is something I'm not pervy to yet but would like to know if this is expected or not.
My goal here is when a user enters in a price I'd like to calculate that in real-time. So far, it is able to do this. HOWEVER, when I first load the page and enter in a set of numbers, for example, 5 in the width and 5 in the length - I get NaN printed to the console. Only after I enter a second number like 55 and 55, will it do the calculation and print it to the console.
I had suspected it has something to do with the initial state so instead of useState()
I switched it to useState(0)
. Instead of producing NaN
I get 0
printed to the console after each number I enter. Again, If I enter 55 and 55 it does the calculation. Why is this and how can I avoid this?
const PPSQ = 12;
const [width, setWidth] = useState()
const [length, setLength] = useState()
function calculate() {
console.log((width * length) * PPSQ);
}
function getWidth(val) {
setWidth(val.target.value)
calculate()
}
function getLength(val) {
setLength(val.target.value)
calculate()
}
<input
className="form-control"
id="length"
name="length"
placeholder="Length"
type="number"
onChange={getLength}
autoComplete="off"
required
/>
<input
className="form-control"
id="width"
name="width"
placeholder="Width"
type="number"
onChange={getWidth}
autoComplete="off"
required
/>
CodePudding user response:
When you call the function calculate() right after the setWidth() or setHeight() you are getting the previous values of the component state (try logging the values in the calculate() to see it). The right thing to do is to wait until the state is changed using the useEffect hook().
function ComponentX() {
const PPSQ = 12;
const [width, setWidth] = useState(0);
const [length, setLength] = useState(0);
useEffect( () => {
console.log((width * length) * PPSQ);
});
function getWidth(val) {
setWidth(val.target.value);
}
function getLength(val) {
setLength(val.target.value)
}
return (
<>
<input
className="form-control"
id="length"
name="length"
placeholder="Length"
type="number"
onChange={getLength}
autoComplete="off"
required
/>
<input
className="form-control"
id="width"
name="width"
placeholder="Width"
type="number"
onChange={getWidth}
autoComplete="off"
required
/>
</>);
}
CodePudding user response:
When you input the first value (e.g. 18 into the length), the other value is not set (e.g. the width).
Thus, when calculate()
outputs [the length] x [the width]
, it equals (in our example) 18 x 0
which equals 0
.
(Or it could equal 18 x NaN
, depending on the initial value).
To fix it, you could only calculate the values if the values are not zero or not NaN:
const PPSQ = 12;
const [width, setWidth] = useState(NaN); // Use NaN
const [length, setLength] = useState(NaN); // Use NaN
function calculate() {
if (!Number.isNaN(width) && !Number.isNaN(length)) {
console.log((width * length) * PPSQ);
}
}
function getWidth(val) {
setWidth(val.target.value)
calculate()
}
function getLength(val) {
setLength(val.target.value)
calculate()
}
<input
className="form-control"
id="length"
name="length"
placeholder="Length"
type="number"
onChange={getLength}
autoComplete="off"
required
/>
<input
className="form-control"
id="width"
name="width"
placeholder="Width"
type="number"
onChange={getWidth}
autoComplete="off"
required
/>