I have 19 inputs and when one of them is changed, all the others reflect the change with a calculation.
<input value={mph} onChange={(e) => cmph(e.target.value, setKph, setMps)}
<input value={kph} onChange={(e) => ckph(e.target.value, setMph, setMps)}
<input value={mps} onChange={(e) => cmps(e.target.value, setKph, setMph)}
For each input I have one state. So I used 19 useState
variables. And all input have an onChange
.
const [mph, setMph] = useState() // miles per hour
const [kph, setKph] = useState() // kiliometers per hour
const [mps, setMps] = useState() // miles per seconds
So when any input is changed, it's onChange
call its unique function do the calculation and set the state 18 times (for each of the other input).
Each input calls it's own function that calculates the value of the others. Its simple math. No DB or endpoint calling.
function cmph(mph, setKph, setMps) {
const kph = mph * 1.60934
setKph(Math.round((kph + Number.EPSILON) * 100) / 100)
const mps = mph / 2.237
setMps(Math.round((mph + Number.EPSILON) * 100) / 100)
}
function ckph(kph, setMph, setMps) {
const mph = kph / 1.60934
setMph(Math.round((mph + Number.EPSILON) * 100) / 100)
const mps = mph / 2.237
setMps(Math.round((mps + Number.EPSILON) * 100) / 100)
}
function cmps(mps, setKph, setMph) {
const mph = mps * 2.237
setMph(mph)
const kph = mph * 1.60934
setKph(kph)
}
All I want is change any of the inputs and all others reflect the new value automatically.
PS: I reduced for three inputs so the example will be smaller. But I have 19 of these.
How can I solve this?
Stack Snippet:
const { useState } = React;
const Example = () => {
const [mph, setMph] = useState(); // miles per hour
const [kph, setKph] = useState(); // kiliometers per hour
const [mps, setMps] = useState(); // miles per seconds
function cmph(mph, setKph, setMps) {
const kph = mph * 1.60934;
setKph(Math.round((kph + Number.EPSILON) * 100) / 100);
const mps = mph / 2.237;
setMps(Math.round((mph + Number.EPSILON) * 100) / 100);
}
function ckph(kph, setMph, setMps) {
const mph = kph / 1.60934;
setMph(Math.round((mph + Number.EPSILON) * 100) / 100);
const mps = mph / 2.237;
setMps(Math.round((mps + Number.EPSILON) * 100) / 100);
}
function cmps(mps, setKph, setMph) {
const mph = mps * 2.237;
setMph(mph);
const kph = mph * 1.60934;
setKph(kph);
}
return (
<div>
<input
value={mph}
size="5"
onChange={(e) => cmph(e.target.value, setKph, setMps)}
/>
<input
value={kph}
size="5"
onChange={(e) => ckph(e.target.value, setMph, setMps)}
/>
<input
value={mps}
size="5"
onChange={(e) => cmps(e.target.value, setKph, setMph)}
/>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Example />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
The problem is that your inputs are controlled, which means their values don't automatically update unless you set the state member you're using to set their value
. The reason it works initially is that by not giving an initial value to useState
, you're defaulting to undefined
, and value={undefined}
makes React think the input is uncontrolled. As soon as you change a value, the inputs go from uncontrolled to controlled, and it stops working. (If you use the development version of the React libs uring development, you'll get a big warning about that.) More about controlled vs. uncontrolled inputs in the documentation.
Instead:
useState
so that they don't default to undefined
change
event of each input, update the state member that controls itFor instance, for mph
:
const mphOnChange = ({ currentTarget: { value } }) => {
setMph(value); // <======================= This is what was missing
cmph(value, setKph, setMps);
};
Working example (those default values may need tweaking):
const { useState } = React;
function cmph(mph, setKph, setMps) {
const kph = mph * 1.60934;
setKph(Math.round((kph + Number.EPSILON) * 100) / 100);
const mps = mph / 2.237;
setMps(Math.round((mph + Number.EPSILON) * 100) / 100);
}
function ckph(kph, setMph, setMps) {
const mph = kph / 1.60934;
setMph(Math.round((mph + Number.EPSILON) * 100) / 100);
const mps = mph / 2.237;
setMps(Math.round((mps + Number.EPSILON) * 100) / 100);
}
function cmps(mps, setKph, setMph) {
const mph = mps * 2.237;
setMph(mph);
const kph = mph * 1.60934;
setKph(kph);
}
const Example = () => {
const [mph, setMph] = useState(0); // miles per hour
const [kph, setKph] = useState(0); // kiliometers per hour
const [mps, setMps] = useState(0); // miles per seconds
const mphOnChange = ({ currentTarget: { value } }) => {
setMph(value);
// Recommend explicit conversion to number here
cmph(value, setKph, setMps);
};
const kphOnChange = ({ currentTarget: { value } }) => {
setKph(value);
// Recommend explicit conversion to number here
ckph(value, setMph, setMps);
};
const mpsOnChange = ({ currentTarget: { value } }) => {
setMps(value);
// Recommend explicit conversion to number here
cmps(value, setKph, setMph);
};
return (
<div>
<input value={mph} size="5" onChange={mphOnChange} />
<input value={kph} size="5" onChange={kphOnChange} />
<input value={mps} size="5" onChange={mpsOnChange} />
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Example />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>