two-way `useEffect` to fetch Currency exchange rate from API implementation not working.

I have a currency converter website which fetches currency values from an API. The value for the two input boxes is taken from 2 states
const Swap = () => {
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',
});

// Rest of the component

<input
id="1"
placeholder="0"
type="number"
value={state1.value}
onChange={handleChange}
/>

// Rest of the component
const Swap = () => {
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',
});

// Rest of the component

<input
id="1"
placeholder="0"
type="number"
value={state1.value}
onChange={handleChange}
/>

// Rest of the component
Now i want the useEffect to fetch currency rate from the API whose response is of the format
{
"from": "USD",
"to": "INR",
"value": "82.3812"
}
{
"from": "USD",
"to": "INR",
"value": "82.3812"
}
I want the value of state 2 to change when state 1 value is set by the user and vice-versa, based on the currency rate 'value' fetched from the API.
setState2({...state2, value: state1.value * response.data.value);

// Like that for state 2 if state 1 is changed by user

setState1({...state1, value: state2.value / response.data.value})

// Like that for state1 when state 2 is changed by user
setState2({...state2, value: state1.value * response.data.value);

// Like that for state 2 if state 1 is changed by user

setState1({...state1, value: state2.value / response.data.value})

// Like that for state1 when state 2 is changed by user
The axios GET request is as follows:
await axios.get('http://localhost:4000/convert", {
params: {
from: state1.value,
to: state2.value
},
})
await axios.get('http://localhost:4000/convert", {
params: {
from: state1.value,
to: state2.value
},
})
How do i write the useeffect to fetch according to my requirements
20 Replies
Wolle
Wolle17mo ago
Just that I understand your problem correctly: - you got your request - you got your state and your question is how to get the response out of axios and into setState inside an useEffect?
Senra
SenraOP17mo ago
yes But it should work both ways. i.e: the api request is triggered when the user changes any one of the inputs. i.e. the state value of either state1 or state2 changes. So if user changes state1, the useEffect will update the state2 value to the converted value.
Wolle
Wolle17mo ago
You may want to use two useEffects, one for each of the states, that sets the other.
useEffect(()=>{ setState2({...state2, value: state1.value * getCourse(state1, state2)}) }, [state1])
useEffect(()=>{ setState1({...state1, value: state2.value * getCourse(state2, state1)}) }, [state2])
useEffect(()=>{ setState2({...state2, value: state1.value * getCourse(state1, state2)}) }, [state1])
useEffect(()=>{ setState1({...state1, value: state2.value * getCourse(state2, state1)}) }, [state2])
getCourse would be the function, which gets the value (I omitted await for simplicity sake)
Senra
SenraOP17mo ago
I tried this out. There is an issue The input value to state1 triggers a rerender so the state 2 value does not even change, and the state1 value itself does not change
Senra
SenraOP17mo ago
Senra
SenraOP17mo ago
it goes into an infinite loop.
Rook
Rook17mo ago
Yeah using two useEffects like that will send you into an infinite loop. Since you said it would be triggered when the user changes the values, maybe trying updating the state withing the handleChange functions for the inputs? So when the user updates the input form for state1, you make an API request for the conversion then update state2, and vice versa
Senra
SenraOP17mo ago
Let me see if I understood correctly. What you are trying to say is to instead of making use of a useEffect hook, incorporate the API call within the handleChange function that changes the input values of both state1 and state2 when triggered by the user.
Rook
Rook17mo ago
Yeah, so when the user updates the input that has state1.value, you update state1 to whatever the user inputs, then send the API request. No clue if it's the best way of doing things tho ¯\_(ツ)_/¯
Senra
SenraOP17mo ago
I will give it a try I tried that. It doesnt work as expected state2 value is changed before API response arrives. This delay will cause the setState2 to set value to be NaN.
Rook
Rook17mo ago
Are you awaiting the API response?
Senra
SenraOP17mo ago
yes
Rook
Rook17mo ago
Can you share your handleChange code for one of the inputs?
Senra
SenraOP17mo ago
function handleChange(event) {
if (event.target.id === '1') {
setState1({ ...state1, value: event.target.value });
} else {
setState2({ ...state2, value: event.target.value });
}
}
function handleChange(event) {
if (event.target.id === '1') {
setState1({ ...state1, value: event.target.value });
} else {
setState2({ ...state2, value: event.target.value });
}
}
I have used a single function to do change both the input values
Rook
Rook17mo ago
You aren't making the API calls to update the state here
Senra
SenraOP17mo ago
oh the updated one? hold on
function handleChange(event) {
if (event.target.id === '1') {
setState1({ ...state1, value: event.target.value });
const res = fetchCurrencyRate(state1, state2);
setState2({ ...state2, value: state1.value * res.data.value });
} else {
setState2({ ...state2, value: event.target.value });
}
}
function handleChange(event) {
if (event.target.id === '1') {
setState1({ ...state1, value: event.target.value });
const res = fetchCurrencyRate(state1, state2);
setState2({ ...state2, value: state1.value * res.data.value });
} else {
setState2({ ...state2, value: event.target.value });
}
}
This is what i tried the fetchCurrencyRate is an async function
Rook
Rook17mo ago
You have to await the result of fetchCurrencyRate then So handleChange will have to be async as well
Senra
SenraOP17mo ago
oh i see BRUH.... it worked
Rook
Rook17mo ago
🥳
Senra
SenraOP17mo ago
async function handleChange(event) {
if (event.target.id === '1') {
setState1({ ...state1, value: event.target.value });
const res = await fetchCurrencyRate(state1, state2);
await setState2({ ...state2, value: state1.value * res });
} else {
setState2({ ...state2, value: event.target.value });
}
}
async function handleChange(event) {
if (event.target.id === '1') {
setState1({ ...state1, value: event.target.value });
const res = await fetchCurrencyRate(state1, state2);
await setState2({ ...state2, value: state1.value * res });
} else {
setState2({ ...state2, value: event.target.value });
}
}
This is the final function I think I now just have to add the same logic in the else part of the loop
Want results from more Discord servers?
Add your server