How to get an asynchronous request from the server using Hook useEffect? - reactjs

Here's how I tried to do it, but it didn't work
useEffect(() => {
try {
const response = async() => {
await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')}
console.log(response.data)
} catch (e) {
console.log(e);
}
})
And so it should look in class components
async componentDidMount() {
try {
const response = await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')}
console.log(response.data)
} catch (e) {
console.log(e);
}
}

You are defining your response as a function (that is never used) rather to do a request call .
Try to split you request function and the useEffect like this (maybe the useEffect don't permit async functions as its parameter).
Maybe this is the correct way to do what you want.
async function request(){
const response = await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')
console.log(response.data)
}
useEffect(async () => {
try {
request()
} catch (e) {
console.log(e);
}
})

I believe you forgat to use the response to convert it to a useable data
useEffect(() => {
try {
const response = async() => {
await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')}
const dataUser = await response.json(); //THIS LINE
console.log(dataUser)
} catch (e) {
console.log(e);
}
})
And so it should look in class components
async componentDidMount() {
try {
const response = await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')}
const dataUser = await response.json(); //THIS LINE
console.log(dataUser)
} catch (e) {
console.log(e);
}
}
I got a few examples in this Github repository

you must define a function and call it after
useEffect(() => {
const fetchData=async()=>{
try {
const response = await axios.get('https://prectik-87c20-default-rtdb.europe-west1.firebasedatabase.app/quizes.json')
console.log(response.data)
} catch (e) {
console.log(e);
}
};
fetchData();
})

Related

Calling an Existing Axios Function in another Function

I'm trying to call an existing function that makes an API request using axios in another function which also makes an API request but its unable to execute the function called. I'm relatively new to axios and react so I'm not sure if I'm missing something here and your help would be much appreciated. Also please note, I can call the API again via axios in the second function but instead of repeating the code I would rather like to do function call.
Function 1:
export const getUsers = () => async (dispatch) => {
try {
const resp = await axiosInstance.get("/api/users/");
dispatch({ type: GET_USERS, payload: resp.data });
} catch (error) {
dispatch(returnErrors(error.response.data, error.response.status));
}
}
Function 2:
export const deactivateUser = (userID) => async (dispatch) => {
try {
const res = await axiosInstance.put(`/api/user/disable/${userID}/`);
dispatch(createMessage({ deactivateUser: res.data }));
} catch (error) {
dispatch(returnErrors(error.response.data, error.response.status));
}
}
What I'm trying to achieve is following:
export const deactivateUser = (userID) => async (dispatch) => {
try {
const res = await axiosInstance.put(`/api/user/disable/${userID}/`);
dispatch(createMessage({ deactivateUser: res.data }));
getUsers(); // This is not getting called....
} catch (error) {
dispatch(returnErrors(error.response.data, error.response.status));
}
}
Any advice or help would be much appreciated!

Call API only after setting loading state

Since, setState in a functional component do not return a promise, how do we set a loading state and then call an API. I have seen people doing it like the one below. I think the axios call will not wait for the loading state to be successfully set before executing. Is there any other better way to solve this without writing the fetch part in an useEffect with the dependency of the loading state?
useEffect(() => {
const fetchProduct = async () => {
setLoading(true);
try {
const response = await axios('http://localhost/products');
setData(response.data);
} catch (err) {
setError(err);
}
setLoading(false);
};
fetchProduct();
}, [productId]);
you can try something like this
useEffect(() => {
const fetchProduct = async () => {
setLoading(true);
await axios.get('http://localhost/products')
.then(response => {
setLoading(false);
setData(response.data);
}).catch(error => {
setLoading(false);
setError(error);
})
};
fetchProduct();
}, [productId]);

Fetch console login twice

I'm trying to fetch from the PokemonAPI but when I console.log my response, it logs twice, and I don't know if that's a problem or not. I'm doing it with Reactjs. My code:
const fetchPokemon = async () => {
try {
const res = await fetch('https://pokeapi.co/api/v2/pokemon/1')
const pokemon = await res.json()
console.log(pokemon)
} catch (err) {
console.log(err)
}
}
fetchPokemon()
In React functional components API call should be placed inside useEffect() function, this will resolve your issue.
useEffect(() => {
async function apiCall() {
const res = await fetch('https://pokeapi.co/api/v2/pokemon/1')
const pokemon = await res.json()
console.log(pokemon)
}
apiCall();
}, []);

How to ensure API data is called and added with .then

I am getting data in useEffect and looping through it to add additional data.
I want to do some calculations on it after all data being added to results, I make the calculations inside if (response.data.next) but after that inside then when I try to access data it prints old data.
How can I make make sure all data added then be able to use it in then?
const [results, setResults] = useState([]);
useEffect(() => {
async function handleAPIRequest(url) {
return await axios
.get(url)
.then(async (response) => {
await setResults((results) => [...results, ...response.data.results]);
if (response.data.next) {
await handleAPIRequest(response.data.next);
}
return results;
})
.then(async () => {
// this is where I want to use results
console.log("resultss: ", results);
});
}
handleAPIRequest(url)
}, []);
I would suggest to keep consistency between async/await or chaining promises. your approach can cause multiple setResults, not sure if that's what you desire. Below, I offer a solution that might suit your needs:
useEffect(() => {
async function handleAPIRequest(url, currentResults = []) {
try {
const response = await axios.get(url)
const nextResults = [...currentResults, ...response.data.results];
if (response.data.next) {
return await handleAPIRequest(response.data.next, nextResults);
}
return nextResults;
} catch (error) {
throw error;
}
}
try {
const finalResults = await handleAPIRequest(url);
setResults(results => [...results, ...finalResults]);
} catch (error) {
// here you can handle error response
console.log(error);
}
}, []);
// to do something after results state is updated use another use effect to accomplish that
useEffect(() => {
// do something on updated results state
}, [JSON.stringify(results)]);
You should change your code in the following way:
const [results, setResults] = useState([]);
useEffect(() => {
const handleAPIRequest = async url => {
const lastResult = await axios.get(url);
setResults([...results, ...lastResult.data.results]);
const toLogResults = [...results, ...lastResult.data.results];
if(response.data.next) {
await handleAPIRequest(response.data.next);
} else {
console.log("The final results are", toLogResults);
}
}
handleAPIRequest(url)
}, []);
The main problem is that results in lines following setResults() are not updated immediately, so the value is the old one.
The toLogResults is used just to display the actual result, it is not needed.

UseEffect not returning response onMount

I am running a test on page load and refresh. It is working well but the test is returning 0;
below is my code;
useEffect(() => {
setLoading(true);
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(getPosition);
} else {
setError("Your browser doesn't support geolocation");
}
const fetchLocations = async () => {
if(currentPos.latitude!==undefined && currentPos.longitude!==undefined) {
try {
const response = await instance
.get("/explore", {
params: {
ll: `${currentPos.latitude},${currentPos.longitude}`
}
})
console.log(response.data.response.groups[0].items);
setLocations(response.data.response.groups[0].items);
setError('')
setLoading(false)
} catch (error) {
setError('Error getting data');
setLoading(false)
}
}
}
fetchLocations()
}, [currentPos.latitude, currentPos.longitude]);
and my test:
What is happening here is on first mount loading... is available. On fetching data from the API is expected toHaveBeenCalledTimes to be 1 instead of returning 0.
it("renders location venues on currentlocation ", async () => {
const {getByText, container} = render(<Venues />);
getByText('Loading...')
await axiosMock.get.mockResolvedValueOnce(() =>
Promise.resolve({ data: {response } })
)
expect(axiosMock.get).toHaveBeenCalledTimes(0)
await waitForElement(() =>
container,
expect(axiosMock.get).toHaveBeenCalledTimes(1)
);
});
How can I fix this test and make it work properly?

Resources