Search code examples
reactjsuse-effect

How to prevent 2 dependent inputs causing an infinite loop when one updates


I have 3 text inputs that accept input from my user

  1. Amount in currency A
  2. A Percentage of currency A
  3. The Percentage value of (2) as currency B

A user can change the values in any of these inputs.

When the percentage value (2) is updated, I need to calculate and update the value displayed in (3)

It is also possible for the user to change the value in (3) and the percentage should be calculated and updated in (2)

I am using useEffect to watch for changes in either and update the other one, but this is causing an infinite loop since as soon as I change one of them, the other gets updated, which in turn causes the useEffect to be run on the input I just changed and so on...

What's the best approach to handle 2 inputs who's values have dependencies on each other like this?


Solution

  • Did not understand what is in the 3rd input so named it val2 and sticked to the formula (1) * (2) = (3).

    In this example we have 3 values.
    If we change val 1, we recalc val 3.
    If we change val 2, we recalc val 3.
    If we change val 3, we recalc val 2.
    This can easily be changed in the logic.

    import { useState } from "react";
    
    export default function App() {
      const [amt1, setAmt1] = useState(1000);
      const [perc1, setPerc1] = useState(5);
      const [val2, setVal2] = useState(50);
    
      const handleAmt1 = (e) => {
        const amt = e.target.value;
        setAmt1(amt);
        setVal2(amt * perc1 * 0.01);
      };
    
      const handlePerc1 = (e) => {
        const perc = e.target.value;
        setPerc1(perc);
        setVal2(amt1 * perc * 0.01);
      };
    
      const handleVal2 = (e) => {
        const val = e.target.value;
        setVal2(val);
        setPerc1((val * 100) / amt1);
      };
    
      return (
        <div className="App">
          <input value={amt1} onChange={handleAmt1} />
          <input value={perc1} onChange={handlePerc1} />
          <input value={val2} onChange={handleVal2} />
        </div>
      );
    }