#avoiding useQuery in controller function

7 messages · Page 1 of 1 (latest)

stark sun
#

@ionic locust how can i avoid the useQuery hook call inside the function?

export const getAllowedUsersProfileImages = authQuery({
  args: { documentId: v.id("documents") },
  handler: async (ctx, args) => {
    const doc = await ctx.db.get(args.documentId)
    let arr:any = doc?.allowedUsers
    const allowedUsersProfileImages = await Promise.all(arr.map(async (id:Id<"users">) => {
      const user = useQuery(api.users.getUser, { userId: id })
      return user?.profileImage
    }))
    return allowedUsersProfileImages
  },
})
ionic locustBOT
#

Let me check the knowledge base for you. One moment! :books:

#

The useQuery hook cannot be used inside a function or a loop as it violates the Rules of Hooks (https://reactjs.org/docs/hooks-rules.html) in React. Hooks must be called at the top level of your React function.

In your case, you are trying to use useQuery inside an async function which is not allowed. Instead, you should fetch the data outside the async function and pass it as an argument.

However, if you want to conditionally skip a query, you can pass "skip" as an argument to useQuery. When "skip" is used, the useQuery doesn't talk to your backend at all and returns undefined. Here is an example from the Convex documentation (https://docs.convex.dev/client/react#skipping-queries):

import React from "react";  
import { useQuery } from "convex/react";  
import { api } from "../convex/_generated/api";  
  
export function App() {  
 const param = new URLSearchParams(window.location.search).get("param");  
 const data = useQuery(  
 api.functions.read,  
 param !== null ? { param } : "skip",  
 );  
 //...  
}  

In your case, you might need to refactor your code to fetch all users first, then filter the allowed users on the client side. If you need to fetch data for each user, consider creating a separate query for that and call it from the component where you need the data.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@stark sun kapa.ai is still learning and improving, please let us know how it did by reacting below

stark sun
#

@ionic locust no that was a convex function for retrieving user profile images. It looks in the documents table for the allowed users and then i want it to search for the profile images of each allowed person and return them so i can use them:

export const getAllowedUsersProfileImages = authQuery({
  args: { documentId: v.id("documents") },
  handler: async (ctx, args) => {
    const doc = await ctx.db.get(args.documentId)
    let arr:any = doc?.allowedUsers
    const allowedUsersProfileImages = await Promise.all(arr.map(async (id:Id<"users">) => {
      const user = useQuery(api.users.getUser, { userId: id })
      return user?.profileImage
    }))
    return allowedUsersProfileImages
  },
})
ionic locustBOT
#

Let me check the knowledge base for you. One moment! :books:

#

The useQuery hook you're trying to use is a React hook and it's not meant to be used in the server-side functions. Instead, you should use the database query methods provided by Convex to fetch the user data.

Here's how you can modify your function to fetch the profile images of allowed users:

export const getAllowedUsersProfileImages = authQuery({
  args: { documentId: v.id("documents") },
  handler: async (ctx, args) => {
    const doc = await ctx.db.get(args.documentId)
    let arr:any = doc?.allowedUsers
    const allowedUsersProfileImages = await Promise.all(arr.map(async (id:Id<"users">) => {
      const user = await ctx.db.get(id)
      return user?.profileImage
    }))
    return allowedUsersProfileImages
  },
})

In this modified function, instead of using useQuery, we're using ctx.db.get(id) to fetch each user's data. This is a server-side method provided by Convex for fetching a document from the database by its ID. The profileImage of each user is then returned in the resulting array.

Please note that this assumes that your user documents have a profileImage field. If the field is named differently, you'll need to adjust the code accordingly.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: