I'm currently working on a React application (with NX set up) where I’m using React Query to manage API calls and state. I have separated my API logic into a service file and created a custom hook to handle the data fetching with React Query. However, I’m encountering an issue where the data returned from my hook is undefined, despite the API call seemingly being successful.
service layer:
export const getUser = async (): Promise<IUser> => {
const { getAccessTokenSilently } = useAuth0()
const token = await getAccessTokenSilently({
authorizationParams: {
audience: 'secret audience here',
scope: 'read:posts',
},
})
const http = useAxios(config.server.apiEndUserUrl, token)
const { data: user } = await http.get<{ data: IUser }>(GET_ACCOUNT)
return user.data // Return the user data
}
hooks:
import { getUser } from '@react-webapp/services'
import { useQuery } from '@tanstack/react-query'
export const useEndUser = () => {
return useQuery({
queryKey: ['getEndUser'],
queryFn: getUser,
})
}
and then the usage:
const [user, setUser] = useState<IUser>(INITIAL_USER)
const { data: fetchedUser, isLoading, error } = useEndUser()
useEffect(() => {
console.log('fetchedUser', fetchedUser)
if (fetchedUser) setUser(fetchedUser)
}, [fetchedUser, isLoading])
output: fetchedUser undefined
but this approach works:
export const useEndUser = () => {
const { getAccessTokenSilently } = useAuth0()
return useQuery({
queryKey: ['endUser'],
queryFn: async () => {
const token = await getAccessTokenSilently({
authorizationParams: {
audience: 'audience here',
scope: 'read:posts',
},
})
const http = useAxios(config.server.apiEndUserUrl, token)
const { data: user } = await http.get<{ data: IUser }>(GET_ACCOUNT)
return user.data
},
})
}
What I want is to have a separation of service and the query hooks, and why is this happening ?
Thanks for advance help !
React with NX set up
Node Version: v20.14.0
"@tanstack/react-query": "^5.59.0",
useAuth0
is a hook, and the rules of hooks forbid calling hooks from functions that aren’t themselves hooks. So this is a violation of the rules of hooks:
export const getUser = async (): Promise<IUser> => {
const { getAccessTokenSilently } = useAuth0()
The second approach works because useAuth0
is called within another hook, useEndUser
.
There are linters that catch these errors, I would encourage you to enable them in your code-base.