Using with tanstack react-query
Tanstack Query is a popular data fetching library for react
applications. We
don’t offer any out the box integration with it (yet), but it does integrate easily with our generated client SDKs.
Here’s a basic example implementation. It’s not perfect, but it should give you a good starting point.
Define the queries and mutations
First we setup a context and define the queries / mutations we’ll be making
import {ApiClient} from "@/generated/clients/client"
import {t_ScanRepositoriesBodySchema} from "@/generated/models"
import {
QueryClient,
UseMutationOptions,
queryOptions,
} from "@tanstack/react-query"
import {createContext, useContext} from "react"
export const QueryOptionsContext = createContext<
ReturnType<typeof createQueryOptions> | null
>(null)
export const useQueryOptions = () => {
const v = useContext(QueryOptionsContext)
if (!v) throw new Error("useQueryOptions must be used within provider")
return v
}
export const createQueryOptions = (
fetchClient: ApiClient,
queryClient: QueryClient,
) => {
const result = {
getSomeResource: (
id: string,
) => {
return queryOptions({
queryKey: [
"getSomeResource",
id
],
queryFn: async () => {
const res = await fetchClient.getSomeResource({
id,
})
if (res.status !== 200) {
throw new Error("request failed", {
cause: new Error(await res.text()),
})
}
return await res.json()
},
})
},
updateSomeResource: (): UseMutationOptions<
void,
Error,
t_ScanRepositoriesBodySchema
> => {
return {
mutationKey: ["updateSomeResource"],
mutationFn: async (id: string, body: t_SomeBodyType) => {
const res = await fetchClient.updateSomeResource({id, requestBody: body})
if (res.status !== 204) {
throw new Error("request failed", {
cause: new Error(await res.text()),
})
}
},
onSuccess: () => {
void queryClient.invalidateQueries({queryKey: ["updateSomeResource"]})
},
}
},
}
return result
}
Initialize the clients
At the root of our application provide the context
import {
QueryOptionsContext,
createQueryOptions,
} from "@/app/providers/query-options"
import {ApiClient} from "@/generated/clients/client"
import {QueryClient, QueryClientProvider} from "@tanstack/react-query"
import {ReactQueryDevtools} from "@tanstack/react-query-devtools"
import {ReactQueryStreamedHydration} from "@tanstack/react-query-next-experimental"
import * as React from "react"
import {useState} from "react"
export function ClientProviders(props: {children: React.ReactNode}) {
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
staleTime: 5_000,
},
},
}),
)
const [fetchClient] = useState(
new ApiClient({
basePath: "http://localhost:3000",
}),
)
return (
<QueryClientProvider client={queryClient}>
<QueryOptionsContext.Provider
value={createQueryOptions(fetchClient, queryClient)}
>
<ReactQueryStreamedHydration>
{props.children}
</ReactQueryStreamedHydration>
<ReactQueryDevtools initialIsOpen={false} />
</QueryOptionsContext.Provider>
</QueryClientProvider>
)
}
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode
}>) {
return (
<html lang="en">
<head>
<meta name="viewport" content="initial-scale=1, width=device-width" />
</head>
<body>
<ClientProviders>
{children}
</ClientProviders>
</body>
</html>
)
}
Use the queries
Finally use the useQueryOptions
hook in conjunction with the normal useQuery
/ useMutation
hooks
to make your requests
import {useQueryOptions} from "@/app/providers/query-options"
import {useMutation, useQuery} from "@tanstack/react-query"
export const SomeComponent = () => {
const queryOptions = useQueryOptions()
const someResource = useQuery(
queryOptions.getSomeResource("123"),
)
const doUpdate = useMutation(queryOptions.updateSomeResource())
return <div>
<h1>{someResource.title}</h1>
<button onClick={() => doUpdate.mutate("123", {title: "new title"})}/>
</div>
}