React useQuery hook running all the time inside the component - javascript

I have a problem where useQuery is always running in my application and I don't why
In my component
import { GET_DATA } from 'apiCalls';
const { loading, error, data } = useQuery('getData', GET_DATA(token));
In my api call
export const GET_DATA = async (token) => {
try {
const res = await axios.get(`${process.env.REACT_APP_SERVER}/api/...`, {
headers: {'auth-token': token},
});
console.log(res);
return res.data;
} catch (err) {
console.log('Error getting data');
return err;
}
}
when I debug my app. The function GET_DATA is always running ALL the time. what is the issue here ?

You must provide the useQuery only the function it wants to run, you must not call it inside useQuery. Provide the token to GET_DATA this way:
EDIT
As #tkdodo said we don't need to use the async function.
const { loading, error, data } = useQuery('getData', ()=>{
return GET_DATA(token);
});
The first solution I provided was this:
const { loading, error, data } = useQuery('getData', async()=>{
const data = await GET_DATA(token);
return data;
});

The root cause is the same as in React-Query, useQuery returns undefined only after loading is complete
The queryFn needs to be a function that returns a promise. GET_DATA does that. But by doing
GET_DATA(token) you directly invoke the function. So you’ll likely want:
() => GET_DATA(token) instead.

Try the following:
// apiCalls.js
export const getData = async (token) => {
try {
const res = await axios.get(`${process.env.REACT_APP_SERVER}/api/...`, {
headers: {'auth-token': token},
});
return res.data;
} catch (err) {
console.log('Error getting data');
return err;
}
// Component.js
import { getData } from 'apiCalls';
function Component(){
const { loading, error, data } = useQuery(
'getData',
()=>GET_DATA(token)
);
return (
<div>...</div>
)
}
useQuery should run in the component and the second parameter should not be a promise, but a function that returns a promise.

Related

Vue 3 using function inside setup

I am doing a simple app and I am using mock-json-server to simulate http request.
I have defined a function to get the info I need :
import { ref } from 'vue'
const getScores = () => {
const scoringPass = ref([])
const error = ref(null)
const load = async () => {
try {
let data = await fetch('http://localhost:8000/scores', {
method: 'get',
headers: {
'content-type': 'application/json'
}})
if (!data.ok) {
throw Error('no data available')
}
scoringPass.value = await data.json()
console.log(scoringPass.value)
} catch (err) {
error.value = err.message
console.log(error.value)
}
}
return { scoringPass, error, load }
}
export default getScores
And I call it in the setup function of my component :
<script lang="ts">
import { defineComponent } from 'vue'
import Pass from '#/components/Pass.vue'
import getScores from '../composables/getScores.js'
export default defineComponent({
setup() {
const numeroDossier = '25020230955000004'
const { scoringPass, error, load } = getScores()
load()
return { numeroDossier, scoringPass, error }
},
components: {
Pass,
},
})
</script>
In the console.log(scoringPass.value) in the function, I can see the data. but the load() function in the setup part does not work and I can't figure out why. It is called though, but I can't get the data.
When I do console.log(load()), I get :
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined
Any help appreciated.
Cheers.
load() is async, so its return value is a Promise. You have to await the call to get the underlying data. However, load() doesn't actually return anything, so you still wouldn't see any data. If you want load() to provide the initial value of scoringPass, load() should return that:
const load = async () => {
try {
⋮
return scoringPass.value
} catch (err) {
⋮
return null
}
}
To get the result of load(), you can wrap the call in an async function to await the call; or chain a .then() callback:
export default defineComponent({
setup() {
⋮
const logLoadResults = async () => console.log(await load())
logLoadResults()
// or
load().then(results => console.log(results))
}
})
Don't mark setup() as async because that would make your component an async component, requiring a <Suspense> in a parent component to render it.

React js cannot return data from function

I have two functions, one is a page that calls for data from a function that gets data to and from a server.
The function that gets data to and from a server:
import React, { useEffect, useState, createRef, lazy, useContext } from "react";
import { UserContext } from "./UserContext";
import jwt_decode from "jwt-decode";
import axios from "axios";
export async function getProtectedAsset(url, user, setUser) {
try {
const res = await axios
.post(url, token)
.then((res) => {
console.log(res.data);
return res.data;
})
.catch((err) => {
console.error(err);
});
} catch (error) {
console.log(error);
throw err;
}
}
The code that calls this function:
useEffect(async () => {
try {
let res = await getProtectedAsset(
"http://127.0.0.1:5002/mypage",
user,
setUser
);
console.log(res);
} catch (error) {
console.error(error.message);
}
}, []);
getProtectedAsset will do a successful console.log(res.data); with the data from the server. The calling function that uses useEffect when doing console.log(res); will write undefined to the console.
Why can't I simply return from the function? Obviously the data is received from the server, but for some reason a function cannot return it? I am very confused
Thank you for your help!
You should not use async in useEffect. This is not supported.
I am not sure why you can't use getProtectedAsse(...).then(res=> {}).
But if you want to run getProtectedAsse() synchronously, try like the following instead.
useEffect(() => {
const asyncInternalFunc = async () => {
try {
let res = await getProtectedAsset(
"http://127.0.0.1:5002/mypage",
user,
setUser
);
console.log(res);
return res;
} catch (error) {
console.error(error.message);
}
}
asyncInternalFunc().then();
}, []);
Updated async function to return the response.
export async function getProtectedAsset(url, user, setUser) {
try {
const res = await axios.post(url, token);
return res;
} catch (error) {
console.log(error);
throw err;
}
}

How to use custom react query hook twice in the same component?

I have a custom hook like so for getting data using useQuery. The hook works fine, no problem there.
const getData = async (url) => {
try{
return await axios(url)
} catch(error){
console.log(error.message)
}
}
export const useGetData = (url, onSuccess) => {
return useQuery('getData', () => getData(url), {onSuccess})
}
However, if I call this hook twice in my component it will only fetch data from the first call even with a different URL. (Ignore the comments typo, that's intentional)
The call in my component:
const { data: commentss, isLoading: commentsIsLoading } = useGetData(`/comments/${params.id}`)
const { data: forumPost, isLoading: forumPostIsLoading } = useGetData(`/forum_posts/${params.id}`)
When I console.log forumPost in this case, it is the array of comments and not the forum post even though I am passing in a different endpoint.
How can I use this hook twice to get different data? Is it possible? I know I can just call parallel queries but I would like to use my hook if possible.
Since useQuery caches based on the queryKey, use the URL in that name
const getData = async(url) => {
try {
return await axios(url)
} catch (error) {
console.log(error.message)
}
}
export const useGetData = (url, onSuccess) => {
return useQuery('getData' + url, () => getData(url), {
onSuccess
})
}
//........
const {
data: commentss,
isLoading: commentsIsLoading
} = useGetData(`/comments/${params.id}`)
const {
data: forumPost,
isLoading: forumPostIsLoading
} = useGetData(`/forum_posts/${params.id}`)

How to get the return value of a async function that returns a promise

So I have a code like this
const getAllProduct = async () => {
let allProduct = "";
let config = {
method: "get",
url: db_base_url + "/products/",
headers: {
Authorization: "Bearer " + token.access.token,
"Content-Type": "application/json",
},
};
try {
let response = await axios(config);
allProduct = response.data.results;
} catch (error) {
console.log(error);
}
console.log(allProduct);
return allProduct;
};
The console.log(allProduct) do prints an array.
The function will be called on the render method of react by
return (<div> {getAllProduct()} </div>)
I've tried to do
return (<div> {console.log(getAllProduct())} </div>
But the console.log on rendering returns to be Promise Object instead of the results array.
How can I go around this?
async functions return a Promise which means their result is not immediately available.
What you need to do is either await the result of calling getAllProduct() function or chain a then() method call.
Looking at your code, i assume that you want to call getAllProduct() function after after your component is rendered. If that's the case, useEffect() hook is where you should call your function.
You could define and call your function inside the useEffect() hook and once the data is available, save that in the local state your component.
First define the local state of the component
const [products, setProducts] = useState([]);
Define and call the getAllProduct() function inside the useEffect() hook.
useEffect(() => {
const getAllProduct = async () => {
...
try {
let response = await axios(config);
allProduct = response.data.results;
// save the data in the state
setProducts(allProduct);
} catch (error) {
console.log(error);
}
};
// call your async function
getAllProduct();
}, []);
Finally, inside the JSX, .map() over the products array and render the products in whatever way you want to render in the DOM.
return (
<div>
{ products.map(prod => {
// return some JSX with the appropriate data
}) }
</div>
);
use
getAllProduct().then(res => console.log(res))
async function always return a promise you use await before call it getAllProduct()
const res = await getAllProduct();
console.log(res)
In my case daisy chaining .then didn't work. Possibly due to fact that I had a helper JS file that held all DB related functions and their data was utilized across various React components.
What did work was daisy chaining await within an async. I modified code where it works for same Component (like in your case). But we can take same logic , put async function in different JS file and use its response in some other component.
Disclaimer : I haven't tested below code as my case was different.
useEffect( () => {
var handleError = function (err) {
console.warn(err);
return new Response(JSON.stringify({
code: 400,
message: 'Error in axios query execution'
}));
};
const getAllProduct = async () => {
let allProduct = "";
...
const response = await ( axios(config).catch(handleError));
allProduct = await response;
return allProduct;
}
},[]);
// Then inside JSX return
getAllProduct().then( data => {
// Make use of data
});

how to solve console log issue in chrome browser

I'm getting data from an API and initially when console it in fetchData function it works but when console it in fetchDailyData function and call this function in another component it didn't work.
How can I solve this issue?
import axios from 'axios';
const url = `https://covid19.mathdro.id/api`;
export const fetchData = async () => {
try {
const { data: { confirmed, recovered, deaths, lastUpdate }} = await axios.get(url);
return { confirmed, recovered, deaths, lastUpdate };
} catch (error) {
}
}
export const fetchDailyData = async () => {
try {
const { data } = await axios.get(`${url}/daily`);
console.log(data); // <<==>> chrome browser is not showing this console log
// fetchDailyData function called in another component
} catch (error) {
}
}
Calling fetchDailyData function in another component
when I call console.log, I can't see the data in console of my browser
const Chart = () => {
const [dailyData, setDailyData] = useState({});
useEffect(() => {
const fetchApi = async () => {
setDailyData(await fetchDailyData());
}
console.log(dailyData);
fetchApi();
});
};
https://covid19.mathdro.id/api/daily which is your url in fetchDailyData doesn't return any data currently at all.
I suppose you have to check if this backend still available. And it is a good practice to check the response status (normally it should return statusCode 200) in response callback.

Categories