TResponse
TResponse

Reputation: 4125

react-query: useQuery returns undefined and component does not rerender

I'm playing around with reactQuery in a little demo app you can see in this repo. The app calls this mock API.

I'm stuck on a an issue where I'm using the useQuery hook to call this function in a product API file:

export const getAllProducts = async (): Promise<Product[]> => {
  const productEndPoint = 'http://localhost:5000/api/product';
  const { data } = await axios.get(productEndPoint);
  return data as Array<Product>;
};

In my ProductTable component I then call this function using:

const { data } = useQuery('products', getAllProducts);

I'm finding the call to the API does get made, and the data is returned. but the table in the grid is always empty.

If I debug I'm seeing the data object returned by useQuery is undefined.

The web request does successfully complete and I can see the data being returned in the network tab under requests in the browser.

I'm suspecting its the way the getAllProducts is structured perhaps or an async await issue but can't quite figure it out.

Can anyone suggest where IO may be going wrong please?

Upvotes: 5

Views: 5699

Answers (2)

Build Though
Build Though

Reputation: 442

Simply use like this At first data is undefined so mapping undefined data gives you a error so we have to use isLoading and if isLoading is true we wont render or map data till then and after isLoading becomes false then we can render or return data.

export const getAllProducts = async (): Promise<Product[]> => {
  const productEndPoint = 'http://localhost:5000/api/product';
  const res= await axios.get(productEndPoint);
  return res.data as Array<Product>;
};

const { data:products , isLoading } = useQuery('products', getAllProducts);

if(isLoading){
return <FallBackView />
}

return (){
products.map(item => item)
}

Upvotes: 1

TResponse
TResponse

Reputation: 4125

I have managed to get this working. For the benefits of others ill share my learnings:

I made a few small changes starting with my api function. Changing the function to the following:

export const getAllProducts = async (): Promise<Product[]> => {
   const response = await axios.get(`api/product`, {
     headers: {
       Accept: 'application/json',
       'Content-Type': 'application/json',
     },
 });

  return response.data as Product[];
};

I do not de-construct the response of the axios call but rather take the data object from it and return is as an Product[]

Then second thing I then changed was in my ProductTable component. Here I told useQuery which type of response to expect by changing the call to :

const { data } = useQuery<Product[], Error>('products', getAllProducts);

Lastly, a rookie mistake on my part: because I was using a mock api in a docker container running on localhost and calling it using http://localhost:5000/api/product I was getting the all to well known network error:

localhost has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present...

So to get around that for the purpose of this exercise I just added a property to the packages.json file: "proxy":"http://localhost:5000",

This has now successfully allowed fetching of the data as I would expect it.

Upvotes: 0

Related Questions