T
Join ServertRPC
❓-help
How to do an async API call in useEffect (T3 stack)
Hey, I have the router below and want to call the
tutor
async in an useCallback
function, but the only method that is available is api.chat.queryTutor.useQuery()
which is a hook where you add the input in advance. But I have it available only in the useCallback
function. is there a way to access the function directly without a hook?export const chatRouter = createTRPCRouter({
tutor: publicProcedure
.input(
z.object({
messages: z.array(
z.object({
id: z.string(),
text: z.string(),
role: z.enum(["user", "system", "assistant"]),
addToPrompt: z.boolean(),
})
),
})
)
.query(async ({ input }): Promise<ChatMessage> => {
// ...
return {
// ...
}
}),
})
You might want a mutation instead?
Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects.
from the docs.
I don't do CRUD ops or perform server side-effects. just accessing a 3rd party API based on parameters from the user interface
so mutation doesnt make sense intuitively
Sure, then using the callback to set some state which drives the query is probably the right way
Calling a query imperatively is a code smell (though not necessarily wrong 100% of the time) and indicates your mindset is wrong
Idk using state as means to drive useQuery is kinda opaque and unintuitive
You think this is bad?
const [chatMessages, setChatMessages] = useRecoilState(chatMessagesState)
const [textareaText, setTextareaText] = useState("")
const [chatLoading, setChatLoading] = useState(false)
const ctx = api.useContext()
const sendUserMessage = useCallback(async () => {
if (textareaText === "") return
if (chatLoading) return
const currentMessages = [...chatMessages]
currentMessages.push({
id: uuidv4(),
role: "user",
text: textareaText,
addToPrompt: true,
})
setChatMessages(currentMessages)
setTextareaText("")
setChatLoading(true)
const answerMessage = await ctx.chat.queryTutor.fetch({
messages: currentMessages,
})
const messagesWithAnswer = [...currentMessages, answerMessage]
setChatMessages(messagesWithAnswer)
setChatLoading(false)
}, [
// ...
])
I think there are some structural issues in both your API and client, yes
useQuery() should just fetch all the messages, and you can use optimistic updates to append the new message, then invalidate the cache so it refetches
there's no server side state, its client side. the backend is an wraps an api that yields results of a machine learning model. thanks so far though, I don't want to waste your time so I'll just stick with this for now
Got it, in that case I'd say this is a mutation
Solution
You are after all getting a new state back from the request, the backend is creating something for you even if it doesn't store it