The point is to use the same custom hook to make different API calls.
The problem:
When I return with {}, it works.
When I return with [], it doesn’t:
It does not enter the ApiGetDogFactsComponent function, it renders the html element, but does not return data.
Note: vscode highlights the return of the function inside {} as any, when inside [] as JSX.Element.
Note: there is a similar post here regarding the subject, but I couldn’t understand the differences.
ApiCallPage.js
// Custom hook for API Facts
import { useApiGetFacts } from '../Hooks/useApiCalls';
export const SeventhPage = () => {
const {ApiGetDogFactsComponent} = useApiGetFacts("dog", "https://dog-api.kinduff.com/api/facts", "Dog");
const {ApiGetCatFactsComponent} = useApiGetFacts("cat", "https://catfact.ninja/fact", "Cat");
return (<>
...
{<ApiGetDogFactsComponent />}
{<ApiGetCatFactsComponent />}
</>)
}
useApiCalls.js
import { useQuery } from '@tanstack/react-query';
export const useApiGetFacts = (type, url, description) => {
const {data, isLoading, isError, refetch, isRefetching} = useQuery([type], async () => {
try {
const res = await fetch(url);
const data = await res.json();
return data;
} catch (error) {
throw error;
}
});
const ApiGetCatFactsComponent = () => {
if (isLoading || isRefetching) {
return (<>
<h1 style={{color: "white"}}>{"Loading ..."}</h1>
</>)
}
if (isError) {
return (<>
<h1 style={{color: "white"}}>{"Error Processing ..."}</h1>
</>)
}
return (<>
<article>
<h3>React Query</h3>
<p>{data?.fact}</p>
<button onClick={refetch}>{description} Fact</button>
</article>
</>)
}
const ApiGetDogFactsComponent = () => {
...samey...
return (<>
<article>
<h3>React Query</h3>
<p>{data.facts[0]}</p>
<button onClick={refetch}>{description} Fact</button>
</article>
</>)
}
return {ApiGetCatFactsComponent, ApiGetDogFactsComponent};
}
Adding, this also works.
const [{ApiGetCatFactsComponent}, {ApiGetDogFactsComponent}] =
[useApiGetFacts("cat", "https://catfact.ninja/fact", "Cat"),
useApiGetFacts("dog", "https://dog-api.kinduff.com/api/facts", "Dog")];
Update for clarification:
This does not work
SeventhPage.js
export const SeventhPage = () => {
...
const [ApiGetDogFactsComponent] = useApiGetFacts("dog", "https://dog-api.kinduff.com/api/facts", "Dog");
const [ApiGetCatFactsComponent] = useApiGetFacts("cat", "https://catfact.ninja/fact", "Cat");
...
}
useApiCalls.js
export const useApiGetFacts = (type, url, description) => {
(same code)
...
return [ApiGetCatFactsComponent, ApiGetDogFactsComponent];
}
2
Answers
This is not a good approach, read both David and TKol comments, but to make it work:
SeventhPage.js
UseApiCalls.js
From my understanding, I should:
Thank you both.
In both of these lines of code:
You are only selecting the first element of the returned array:
Regardless of what you name them, both of them are rferences to
ApiGetCatFactsComponent
.Basically you’ve simply discovered that object properties are named and array elements are positional. If the original/returned name matters, use object properties.
As an aside… If you have to call your hook twice depending on what arguments you pass to it, you might consider a different design. Maybe two different hooks, maybe the hook internally knows the URLs and returns both functions, maybe something else. It’s hard to tell based on what you’ve built.
But, just looking at each call to
useApiGetFacts
… All three of the function parameters are telling it whether you want a "cat" or a "dog". That’s a lot of repetition.Taking it a step further… hooks shouldn’t really return components in the first place. Hooks are great for providing useful helper functions, maintaining state in those functions, etc. But this feels like an unintuitive mixture of hooks and components.
Think of hooks and components as structurally similar, but the former returns data (or functions which return data) whereas the latter returns JSX.