I am making a React application for a currency converter website. I have two <input> fields where the user can input the number to get the exchange rate as shown here:
Screenshot of Component
The <input> fields are as follows:
<>
<input
id="1"
placeholder="0"
type="number"
value={state1.value}
onChange={handleChange}
disabled={loading}
/>
// rest of the component
<input
id="2"
placeholder="0"
type="number"
value={state2.value}
onChange={handleChange}
disabled={loading}
/>
The states for the input fields are:
const [state1, setState1] = useState({
value: '',
currency: 'USD',
src: 'https://hatscripts.github.io/circle-flags/flags/us.svg',
});
const [state2, setState2] = useState({
value: '',
currency: 'INR',
src: 'https://hatscripts.github.io/circle-flags/flags/in.svg',
});
I want the state2 to be updated when the user types in state1. And vice-versa. I don't want the auto-update of state2 again changing state1. The state change should happen only when the user gives input.
I have tried using session state to avoid unnecessary API calls. It solves the problem except for the infinite recursion.
I have already written a useEffect for state1 which works as expected. Now I want to do the same for state2 without an infinite useEffect loop.
async function fetchCurrencyRate1(from, to) {
setLoading(true);
try {
const response = await axios.get('http://localhost:4000/convert', {
params: {
from: from.currency,
to: to.currency,
},
});
setState2((state2) => ({
...state2,
value: (from.value * response.data.value).toFixed(4),
}));
console.log(response.data);
} catch (error) {
console.error(error);
}
setLoading(false);
}
useEffect(() => {
setTimeout(() => {
state1.value && fetchCurrencyRate1(state1, { ...state2 });
if (state1.value === '') setState2({ ...state2, value: '' });
}, 2000);
}, [state1]);
The infinite render occurs because the
useEffectofstate1will fire each timestate1take a new value and since inside the effect you updatestate2and this triggersuseEffectofstate2and the code there updatesstate1thenuseEffectofstate1will be called infinitely becausestate1is an object so its value is always new.you don't need
useEffectfor that, also you don't want to rerender the component twice on each input change you can simply make two separatehandleChangefunctions for each input and make your logic in each one of themsomething like this: